Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 95 additions & 37 deletions src/parser/analyze-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,30 +90,65 @@ export function analyzeReactiveScope(scopeManager: ScopeManager): void {
* Analyze store scope. e.g. $count
*/
export function analyzeStoreScope(scopeManager: ScopeManager): void {
const moduleScope = scopeManager.scopes.find(
(scope) => scope.type === "module",
)
if (!moduleScope) {
return
}
const toBeMarkAsUsedReferences: Reference[] = []

for (const reference of [...scopeManager.globalScope.through]) {
if (reference.identifier.name.startsWith("$")) {
const realName = reference.identifier.name.slice(1)
const moduleScope = scopeManager.scopes.find(
(scope) => scope.type === "module",
)
if (moduleScope) {
const variable = moduleScope?.set.get(realName)
if (variable) {
// It does not write directly to the original variable.
// Therefore, this variable is always a reference.
reference.isWrite = () => false
reference.isWriteOnly = () => false
reference.isReadWrite = () => false
reference.isReadOnly = () => true
reference.isRead = () => true

variable.references.push(reference)
reference.resolved = variable
removeReferenceFromThrough(reference, moduleScope)
const variable = moduleScope.set.get(realName)
if (variable) {
if (reference.isWriteOnly()) {
// Need mark as used
toBeMarkAsUsedReferences.push(reference)
}

// It does not write directly to the original variable.
// Therefore, this variable is always a reference.
reference.isWrite = () => false
reference.isWriteOnly = () => false
reference.isReadWrite = () => false
reference.isReadOnly = () => true
reference.isRead = () => true

variable.references.push(reference)
reference.resolved = variable
removeReferenceFromThrough(reference, moduleScope)
}
}
}

for (const variable of new Set(
toBeMarkAsUsedReferences.map((ref) => ref.resolved!),
)) {
if (
variable.references.some(
(ref) =>
!toBeMarkAsUsedReferences.includes(ref) &&
ref.identifier !== variable.identifiers[0],
)
) {
// It is already used.
continue
}

// Add the virtual reference for reading.
;(
addVirtualReference(
variable.identifiers[0],
variable,
moduleScope,
{
read: true,
},
) as any
).svelteMarkAsUsed = true
}
}

/** Transform props exports */
Expand Down Expand Up @@ -163,27 +198,25 @@ export function analyzePropsScope(
}

// Add the virtual reference for writing.
const reference = new Reference()
;(reference as any).sveltePropReference = true
reference.from = scope
reference.identifier = {
...node,
// @ts-expect-error -- ignore
parent: body,
loc: {
start: { ...node.loc!.start },
end: { ...node.loc!.end },
const reference = addVirtualReference(
{
...node,
// @ts-expect-error -- ignore
parent: body,
loc: {
start: { ...node.loc!.start },
end: { ...node.loc!.end },
},
range: [...node.range!],
},
range: [...node.range!],
}
reference.isWrite = () => true
reference.isWriteOnly = () => false
reference.isRead = () => true
reference.isReadOnly = () => false
reference.isReadWrite = () => true

variable.references.push(reference)
reference.resolved = variable
variable,
scope,
{
write: true,
read: true,
},
)
;(reference as any).sveltePropReference = true
}
}
}
Expand All @@ -210,6 +243,31 @@ function removeReferenceFromThrough(reference: Reference, baseScope: Scope) {
}
}

/**
* Add the virtual reference.
*/
function addVirtualReference(
node: ESTree.Identifier,
variable: Variable,
scope: Scope,
readWrite: { read?: boolean; write?: boolean },
) {
const reference = new Reference()
;(reference as any).svelteVirtualReference = true
reference.from = scope
reference.identifier = node
reference.isWrite = () => Boolean(readWrite.write)
reference.isWriteOnly = () => Boolean(readWrite.write) && !readWrite.read
reference.isRead = () => Boolean(readWrite.read)
reference.isReadOnly = () => Boolean(readWrite.read) && !readWrite.write
reference.isReadWrite = () => Boolean(readWrite.read && readWrite.write)

variable.references.push(reference)
reference.resolved = variable

return reference
}

/** Get parent node */
function getParent(node: ESTree.Node): ESTree.Node | null {
return (node as any).parent
Expand Down
8 changes: 0 additions & 8 deletions tests/fixtures/parser/ast/$var-no-unused-vars-result.json

This file was deleted.

40 changes: 40 additions & 0 deletions tests/fixtures/parser/ast/$var-scope-output.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,46 @@
}
}
}
},
{
"identifier": {
"type": "Identifier",
"name": "a",
"range": [
20,
21
],
"loc": {
"start": {
"line": 2,
"column": 11
},
"end": {
"line": 2,
"column": 12
}
}
},
"from": "module",
"init": null,
"resolved": {
"type": "Identifier",
"name": "a",
"range": [
20,
21
],
"loc": {
"start": {
"line": 2,
"column": 11
},
"end": {
"line": 2,
"column": 12
}
}
}
}
]
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,46 @@
}
}
}
},
{
"identifier": {
"type": "Identifier",
"name": "imported",
"range": [
19,
27
],
"loc": {
"start": {
"line": 2,
"column": 10
},
"end": {
"line": 2,
"column": 18
}
}
},
"from": "module",
"init": null,
"resolved": {
"type": "Identifier",
"name": "imported",
"range": [
19,
27
],
"loc": {
"start": {
"line": 2,
"column": 10
},
"end": {
"line": 2,
"column": 18
}
}
}
}
]
},
Expand Down Expand Up @@ -624,6 +664,46 @@
}
}
}
},
{
"identifier": {
"type": "Identifier",
"name": "writeOnly",
"range": [
69,
78
],
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 16
}
}
},
"from": "module",
"init": null,
"resolved": {
"type": "Identifier",
"name": "writeOnly",
"range": [
69,
78
],
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 16
}
}
}
}
]
},
Expand Down