@trojanbox-vcp-test/site-edit-engine 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.js +127 -2
- package/dist/internal/protocol/operation.d.ts +2 -0
- package/dist/internal/protocol/render.d.ts +3 -30
- package/dist/internal/protocol.d.ts +1 -1
- package/dist/next-app-router.js +1 -140
- package/dist/preview-runtime.d.ts +249 -303
- package/dist/runtime-sync.d.ts +8 -8
- package/dist/runtime.d.ts +1 -127
- package/dist/site-edit-instrumentation.d.ts +1 -1
- package/dist/source-watcher.js +1 -150
- package/dist/types.d.ts +12 -14
- package/dist/webpack-loader.cjs +50 -588
- package/package.json +2 -2
- package/dist/execute-integration/execute-fixture-harness.d.ts +0 -25
- package/dist/execute-integration/execute-fixture-harness.js +0 -37
- package/dist/internal/ast/diagnostics/index.d.ts +0 -5
- package/dist/internal/ast/diagnostics/index.js +0 -25
- package/dist/internal/ast/history/index.d.ts +0 -15
- package/dist/internal/ast/history/index.js +0 -62
- package/dist/internal/ast/index.d.ts +0 -8
- package/dist/internal/ast/index.js +0 -5
- package/dist/internal/ast/locators/index.d.ts +0 -1
- package/dist/internal/ast/locators/index.js +0 -1
- package/dist/internal/ast/locators/resolve-locator.d.ts +0 -16
- package/dist/internal/ast/locators/resolve-locator.js +0 -920
- package/dist/internal/ast/parser/SourceParser.d.ts +0 -30
- package/dist/internal/ast/parser/SourceParser.js +0 -49
- package/dist/internal/ast/parser/index.d.ts +0 -21
- package/dist/internal/ast/parser/index.js +0 -64
- package/dist/internal/ast/primitives/conditional/conditional-primitives.d.ts +0 -18
- package/dist/internal/ast/primitives/conditional/conditional-primitives.js +0 -237
- package/dist/internal/ast/primitives/conditional/index.d.ts +0 -1
- package/dist/internal/ast/primitives/conditional/index.js +0 -1
- package/dist/internal/ast/primitives/imports/add-import.d.ts +0 -18
- package/dist/internal/ast/primitives/imports/add-import.js +0 -111
- package/dist/internal/ast/primitives/imports/index.d.ts +0 -2
- package/dist/internal/ast/primitives/imports/index.js +0 -2
- package/dist/internal/ast/primitives/imports/remove-import.d.ts +0 -15
- package/dist/internal/ast/primitives/imports/remove-import.js +0 -72
- package/dist/internal/ast/primitives/index.d.ts +0 -10
- package/dist/internal/ast/primitives/index.js +0 -10
- package/dist/internal/ast/primitives/jsx/index.d.ts +0 -4
- package/dist/internal/ast/primitives/jsx/index.js +0 -4
- package/dist/internal/ast/primitives/jsx/insert-child.d.ts +0 -11
- package/dist/internal/ast/primitives/jsx/insert-child.js +0 -69
- package/dist/internal/ast/primitives/jsx/move-node.d.ts +0 -9
- package/dist/internal/ast/primitives/jsx/move-node.js +0 -76
- package/dist/internal/ast/primitives/jsx/remove-node.d.ts +0 -7
- package/dist/internal/ast/primitives/jsx/remove-node.js +0 -36
- package/dist/internal/ast/primitives/jsx/update-text.d.ts +0 -8
- package/dist/internal/ast/primitives/jsx/update-text.js +0 -81
- package/dist/internal/ast/primitives/next/index.d.ts +0 -1
- package/dist/internal/ast/primitives/next/index.js +0 -1
- package/dist/internal/ast/primitives/next/next-primitives.d.ts +0 -43
- package/dist/internal/ast/primitives/next/next-primitives.js +0 -211
- package/dist/internal/ast/primitives/shared.d.ts +0 -60
- package/dist/internal/ast/primitives/shared.js +0 -176
- package/dist/internal/ast/primitives/style/class-expression.d.ts +0 -23
- package/dist/internal/ast/primitives/style/class-expression.js +0 -174
- package/dist/internal/ast/primitives/style/index.d.ts +0 -1
- package/dist/internal/ast/primitives/style/index.js +0 -1
- package/dist/internal/ast/primitives/style/style-primitives.d.ts +0 -49
- package/dist/internal/ast/primitives/style/style-primitives.js +0 -555
- package/dist/internal/ast/primitives/values/index.d.ts +0 -1
- package/dist/internal/ast/primitives/values/index.js +0 -1
- package/dist/internal/ast/primitives/values/value-primitives.d.ts +0 -42
- package/dist/internal/ast/primitives/values/value-primitives.js +0 -158
- package/dist/internal/ast/printer/SourcePrinter.d.ts +0 -21
- package/dist/internal/ast/printer/SourcePrinter.js +0 -76
- package/dist/internal/ast/printer/index.d.ts +0 -6
- package/dist/internal/ast/printer/index.js +0 -126
- package/dist/internal/ast/types.d.ts +0 -190
- package/dist/internal/ast/types.js +0 -1
- package/dist/internal/capability/capability-resolver.d.ts +0 -16
- package/dist/internal/capability/capability-resolver.js +0 -127
- package/dist/internal/classname-source.d.ts +0 -24
- package/dist/internal/classname-source.js +0 -220
- package/dist/internal/contracts/IEditEngineRuntime.d.ts +0 -18
- package/dist/internal/contracts/IEditEngineRuntime.js +0 -1
- package/dist/internal/domain/EditDiagnostic.d.ts +0 -38
- package/dist/internal/domain/EditDiagnostic.js +0 -43
- package/dist/internal/events/event-bus.d.ts +0 -14
- package/dist/internal/events/event-bus.js +0 -21
- package/dist/internal/graph/graph-builder.d.ts +0 -12
- package/dist/internal/graph/graph-builder.js +0 -1371
- package/dist/internal/graph/import-resolver.d.ts +0 -31
- package/dist/internal/graph/import-resolver.js +0 -109
- package/dist/internal/graph/project-graph-builder.d.ts +0 -32
- package/dist/internal/graph/project-graph-builder.js +0 -133
- package/dist/internal/graph/types.d.ts +0 -114
- package/dist/internal/graph/types.js +0 -6
- package/dist/internal/history/undo-redo.d.ts +0 -28
- package/dist/internal/history/undo-redo.js +0 -42
- package/dist/internal/index.d.ts +0 -2
- package/dist/internal/index.js +0 -1
- package/dist/internal/planner/planner.d.ts +0 -104
- package/dist/internal/planner/planner.js +0 -2533
- package/dist/internal/planner/types.d.ts +0 -275
- package/dist/internal/planner/types.js +0 -6
- package/dist/internal/protocol/boundary.js +0 -3
- package/dist/internal/protocol/capability.js +0 -8
- package/dist/internal/protocol/error.js +0 -38
- package/dist/internal/protocol/event.js +0 -3
- package/dist/internal/protocol/identity.js +0 -30
- package/dist/internal/protocol/operation.js +0 -8
- package/dist/internal/protocol/render.js +0 -3
- package/dist/internal/protocol.js +0 -2
- package/dist/internal/provenance/binding-graph.d.ts +0 -39
- package/dist/internal/provenance/binding-graph.js +0 -184
- package/dist/internal/provenance/capability-policy.d.ts +0 -15
- package/dist/internal/provenance/capability-policy.js +0 -96
- package/dist/internal/provenance/data-source-classifier.d.ts +0 -14
- package/dist/internal/provenance/data-source-classifier.js +0 -281
- package/dist/internal/provenance/resolve-text-provenance.d.ts +0 -45
- package/dist/internal/provenance/resolve-text-provenance.js +0 -3090
- package/dist/internal/provenance/types.d.ts +0 -89
- package/dist/internal/provenance/types.js +0 -1
- package/dist/internal/render/component-semantic.d.ts +0 -11
- package/dist/internal/render/component-semantic.js +0 -141
- package/dist/internal/render/content-model.d.ts +0 -3
- package/dist/internal/render/content-model.js +0 -89
- package/dist/internal/render/media-model.d.ts +0 -3
- package/dist/internal/render/media-model.js +0 -45
- package/dist/internal/render/provenance-types.d.ts +0 -33
- package/dist/internal/render/provenance-types.js +0 -1
- package/dist/internal/render/render-projection.d.ts +0 -24
- package/dist/internal/render/render-projection.js +0 -281
- package/dist/internal/render/tailwind-style-model.d.ts +0 -19
- package/dist/internal/render/tailwind-style-model.js +0 -1187
- package/dist/internal/runtime/EditEngineRuntime.d.ts +0 -25
- package/dist/internal/runtime/EditEngineRuntime.js +0 -89
- package/dist/internal/runtime/EditEngineRuntimeSnapshot.d.ts +0 -31
- package/dist/internal/runtime/EditEngineRuntimeSnapshot.js +0 -15
- package/dist/internal/runtime/InternalEditEngine.d.ts +0 -44
- package/dist/internal/runtime/InternalEditEngine.js +0 -1391
- package/dist/internal/runtime.d.ts +0 -3
- package/dist/internal/runtime.js +0 -1
- package/dist/internal/topology/topology.d.ts +0 -6
- package/dist/internal/topology/topology.js +0 -98
- package/dist/internal/topology/types.d.ts +0 -35
- package/dist/internal/topology/types.js +0 -5
- package/dist/internal/types.d.ts +0 -1
- package/dist/internal/types.js +0 -1
- package/dist/internal/writeback/in-memory-fs.d.ts +0 -7
- package/dist/internal/writeback/in-memory-fs.js +0 -44
- package/dist/internal/writeback/types.d.ts +0 -45
- package/dist/internal/writeback/types.js +0 -7
- package/dist/internal/writeback/writeback-service.d.ts +0 -7
- package/dist/internal/writeback/writeback-service.js +0 -568
- package/dist/internal-adapter.d.ts +0 -18
- package/dist/internal-adapter.js +0 -350
- package/dist/next-app-router-fs.js +0 -64
- package/dist/preview-runtime.js +0 -102
- package/dist/public-file-system.js +0 -1
- package/dist/runtime-sync.js +0 -321
- package/dist/runtime.js +0 -134
- package/dist/site-edit-instrumentation.js +0 -322
- package/dist/snapshot-file-system.d.ts +0 -19
- package/dist/snapshot-file-system.js +0 -49
- package/dist/source-writeback-test-harness.d.ts +0 -244
- package/dist/source-writeback-test-harness.js +0 -119
- package/dist/types.js +0 -1
|
@@ -1,920 +0,0 @@
|
|
|
1
|
-
import _traverse from "@babel/traverse";
|
|
2
|
-
import { createDiagnostic, locatorFailure } from "../diagnostics/index.js";
|
|
3
|
-
import { parseForLocator } from "../parser/index.js";
|
|
4
|
-
/* node:coverage ignore next */
|
|
5
|
-
const traverse = (typeof _traverse === "function" ? _traverse : _traverse.default);
|
|
6
|
-
const siblingOrdinalCache = new WeakMap();
|
|
7
|
-
const structuralChildrenCache = new WeakMap();
|
|
8
|
-
export function resolveLocator(source, locator) {
|
|
9
|
-
const parsed = parseForLocator(source, locator);
|
|
10
|
-
if (!parsed.ok) {
|
|
11
|
-
return locatorFailure(source, parsed.diagnostic.code, parsed.diagnostic.message, locator.kind);
|
|
12
|
-
}
|
|
13
|
-
const result = resolveLocatorPath(parsed.ast, locator);
|
|
14
|
-
if (!result.ok) {
|
|
15
|
-
return locatorFailure(source, result.diagnostic.code, result.diagnostic.message, locator.kind, result.diagnostic.details);
|
|
16
|
-
}
|
|
17
|
-
return {
|
|
18
|
-
ok: true,
|
|
19
|
-
match: {
|
|
20
|
-
locatorKind: result.match.locatorKind,
|
|
21
|
-
node: result.match.node,
|
|
22
|
-
start: result.match.start,
|
|
23
|
-
end: result.match.end,
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export function resolveLocatorPath(ast, locator) {
|
|
28
|
-
if (locator.kind === "jsx-node") {
|
|
29
|
-
return resolveJsxNodeLocator(ast, locator);
|
|
30
|
-
}
|
|
31
|
-
if (locator.kind === "jsx-attribute") {
|
|
32
|
-
return resolveJsxAttributeLocator(ast, locator);
|
|
33
|
-
}
|
|
34
|
-
if (locator.kind === "value") {
|
|
35
|
-
return resolveValueLocator(ast, locator);
|
|
36
|
-
}
|
|
37
|
-
if (locator.kind === "expression") {
|
|
38
|
-
return resolveExpressionLocator(ast, locator);
|
|
39
|
-
}
|
|
40
|
-
if (locator.kind === "directive") {
|
|
41
|
-
return resolveDirectiveLocator(ast, locator);
|
|
42
|
-
}
|
|
43
|
-
if (locator.kind === "export") {
|
|
44
|
-
return resolveExportLocator(ast, locator);
|
|
45
|
-
}
|
|
46
|
-
return {
|
|
47
|
-
ok: false,
|
|
48
|
-
diagnostic: createDiagnostic("unsupported-syntax", `Unsupported locator kind: ${locator.kind}`),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
function resolveJsxNodeLocator(ast, locator) {
|
|
52
|
-
return locator.strategy === "source-range"
|
|
53
|
-
? resolveJsxNodeBySourceRange(ast, locator)
|
|
54
|
-
: resolveJsxNodeByStructuralPath(ast, locator);
|
|
55
|
-
}
|
|
56
|
-
function resolveJsxNodeBySourceRange(ast, locator) {
|
|
57
|
-
let best = null;
|
|
58
|
-
traverse(ast, {
|
|
59
|
-
JSXElement(path) {
|
|
60
|
-
if (!hasExactRange(path.node, locator.sourceRange)) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const candidate = toInternalMatch("jsx-node", path);
|
|
64
|
-
if (!candidate) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (!best) {
|
|
68
|
-
best = candidate;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (candidate.end - candidate.start < best.end - best.start) {
|
|
72
|
-
best = candidate;
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
if (!best)
|
|
77
|
-
return failLocator("jsx-node", "locator-miss", "JSX node not found for source-range locator");
|
|
78
|
-
const bestMatch = best;
|
|
79
|
-
if (locator.expectedIdentity &&
|
|
80
|
-
!matchesExpectedJsxIdentity(bestMatch.path, locator.expectedIdentity)) {
|
|
81
|
-
return failLocator("jsx-node", "locator-miss", "JSX node failed expected identity validation");
|
|
82
|
-
}
|
|
83
|
-
return { ok: true, match: bestMatch };
|
|
84
|
-
}
|
|
85
|
-
function resolveJsxNodeByStructuralPath(ast, locator) {
|
|
86
|
-
// 检测 fragment root 作为编辑目标 — 返回明确 unsupported-syntax
|
|
87
|
-
if (locator.structuralPath === "") {
|
|
88
|
-
const componentFuncPath = findComponentFunctionPath(ast, locator.component);
|
|
89
|
-
if (componentFuncPath) {
|
|
90
|
-
const fragmentResult = checkComponentFragmentRoot(componentFuncPath);
|
|
91
|
-
if (fragmentResult) {
|
|
92
|
-
return fragmentResult;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
let match = null;
|
|
97
|
-
traverse(ast, {
|
|
98
|
-
JSXElement(path) {
|
|
99
|
-
const candidateComponent = getEnclosingComponentName(path);
|
|
100
|
-
if (candidateComponent !== locator.component) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (computeJsxStructuralPath(path) !== locator.structuralPath) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const candidate = toInternalMatch("jsx-node", path);
|
|
107
|
-
if (!candidate) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
if (locator.expectedRange &&
|
|
111
|
-
!matchesRange(path.node.loc, locator.expectedRange)) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
/* node:coverage ignore start */
|
|
115
|
-
match = candidate;
|
|
116
|
-
path.stop();
|
|
117
|
-
/* node:coverage ignore stop */
|
|
118
|
-
},
|
|
119
|
-
JSXFragment(path) {
|
|
120
|
-
const candidateComponent = getEnclosingComponentName(path);
|
|
121
|
-
if (candidateComponent !== locator.component) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (computeJsxStructuralPath(path) !==
|
|
125
|
-
locator.structuralPath) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const candidate = toInternalMatch("jsx-node", path);
|
|
129
|
-
if (!candidate) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
if (locator.expectedRange &&
|
|
133
|
-
!matchesRange(path.node.loc, locator.expectedRange)) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
/* node:coverage ignore start */
|
|
137
|
-
match = candidate;
|
|
138
|
-
path.stop();
|
|
139
|
-
/* node:coverage ignore stop */
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
if (!match) {
|
|
143
|
-
return failLocator("jsx-node", "locator-miss", "JSX node not found for structural-path locator");
|
|
144
|
-
}
|
|
145
|
-
return { ok: true, match };
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* 查找组件对应的函数节点路径
|
|
149
|
-
* 支持 FunctionDeclaration、ArrowFunctionExpression、FunctionExpression
|
|
150
|
-
*/
|
|
151
|
-
function findComponentFunctionPath(ast, componentName) {
|
|
152
|
-
let result = null;
|
|
153
|
-
traverse(ast, {
|
|
154
|
-
FunctionDeclaration(path) {
|
|
155
|
-
if (path.node.id?.name === componentName) {
|
|
156
|
-
result = path;
|
|
157
|
-
path.stop();
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
VariableDeclarator(path) {
|
|
161
|
-
if (path.node.id.type === "Identifier" &&
|
|
162
|
-
path.node.id.name === componentName) {
|
|
163
|
-
const init = path.get("init");
|
|
164
|
-
if (init.isArrowFunctionExpression() || init.isFunctionExpression()) {
|
|
165
|
-
result = init;
|
|
166
|
-
}
|
|
167
|
-
path.stop();
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* 检查组件函数是否返回 JSXFragment 作为根节点
|
|
175
|
-
* 返回 unsupported-syntax diagnostic 或 null
|
|
176
|
-
*/
|
|
177
|
-
function checkComponentFragmentRoot(funcPath) {
|
|
178
|
-
if (funcPath.isArrowFunctionExpression()) {
|
|
179
|
-
const body = funcPath.get("body");
|
|
180
|
-
// 块体箭头函数:检查 return 语句
|
|
181
|
-
if (body.isBlockStatement()) {
|
|
182
|
-
const returnStmt = body
|
|
183
|
-
.get("body")
|
|
184
|
-
.find((stmt) => stmt.isReturnStatement());
|
|
185
|
-
if (returnStmt) {
|
|
186
|
-
const argument = returnStmt.get("argument");
|
|
187
|
-
const target = argument.isParenthesizedExpression()
|
|
188
|
-
? argument.get("expression")
|
|
189
|
-
: argument;
|
|
190
|
-
if (target.isJSXFragment()) {
|
|
191
|
-
return failLocator("jsx-node", "unsupported-syntax", "JSXFragment is not a supported edit target");
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
// 简洁体箭头函数:直接检查 body
|
|
197
|
-
const target = body.isParenthesizedExpression()
|
|
198
|
-
? body.get("expression")
|
|
199
|
-
: body;
|
|
200
|
-
if (target.isJSXFragment()) {
|
|
201
|
-
return failLocator("jsx-node", "unsupported-syntax", "JSXFragment is not a supported edit target");
|
|
202
|
-
}
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
if (funcPath.isFunctionDeclaration() || funcPath.isFunctionExpression()) {
|
|
206
|
-
const body = funcPath.get("body");
|
|
207
|
-
if (body.isBlockStatement()) {
|
|
208
|
-
const returnStmt = body
|
|
209
|
-
.get("body")
|
|
210
|
-
.find((stmt) => stmt.isReturnStatement());
|
|
211
|
-
if (returnStmt) {
|
|
212
|
-
const argument = returnStmt.get("argument");
|
|
213
|
-
// 处理 return ( <></> ) 的 ParenthesizedExpression 包裹
|
|
214
|
-
const target = argument.isParenthesizedExpression()
|
|
215
|
-
? argument.get("expression")
|
|
216
|
-
: argument;
|
|
217
|
-
if (target.isJSXFragment()) {
|
|
218
|
-
return failLocator("jsx-node", "unsupported-syntax", "JSXFragment is not a supported edit target");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
function resolveJsxAttributeLocator(ast, locator) {
|
|
226
|
-
const elementMatch = resolveJsxNodeLocator(ast, locator.element);
|
|
227
|
-
if (!elementMatch.ok) {
|
|
228
|
-
return elementMatch;
|
|
229
|
-
}
|
|
230
|
-
const elementPath = elementMatch.match.path;
|
|
231
|
-
const openingElement = elementPath.get("openingElement");
|
|
232
|
-
const attributes = openingElement.get("attributes");
|
|
233
|
-
const attributePath = attributes.find((attribute) => isNamedJsxAttributePath(attribute, locator.name));
|
|
234
|
-
if (!attributePath || !attributePath.isJSXAttribute()) {
|
|
235
|
-
return failLocator("jsx-attribute", "locator-miss", `JSX attribute '${locator.name}' not found`);
|
|
236
|
-
}
|
|
237
|
-
const match = toInternalMatch("jsx-attribute", attributePath);
|
|
238
|
-
if (!match) {
|
|
239
|
-
return failLocator("jsx-attribute", "locator-miss", `JSX attribute '${locator.name}' has no source range`);
|
|
240
|
-
}
|
|
241
|
-
return { ok: true, match };
|
|
242
|
-
}
|
|
243
|
-
function resolveValueLocator(ast, locator) {
|
|
244
|
-
const rootPath = resolveValueRootPath(ast, locator);
|
|
245
|
-
if (!rootPath.ok) {
|
|
246
|
-
return rootPath;
|
|
247
|
-
}
|
|
248
|
-
const resolvedPath = followValuePath(rootPath.match.path, locator.path ?? []);
|
|
249
|
-
if (!resolvedPath.ok) {
|
|
250
|
-
return resolvedPath;
|
|
251
|
-
}
|
|
252
|
-
if (locator.expectedRange &&
|
|
253
|
-
!matchesRange(resolvedPath.match.path.node.loc, locator.expectedRange)) {
|
|
254
|
-
return failLocator("value", "locator-miss", "Resolved value does not match expected range");
|
|
255
|
-
}
|
|
256
|
-
return { ok: true, match: resolvedPath.match };
|
|
257
|
-
}
|
|
258
|
-
function resolveExpressionLocator(ast, locator) {
|
|
259
|
-
let match = null;
|
|
260
|
-
traverse(ast, {
|
|
261
|
-
Identifier(path) {
|
|
262
|
-
if (!isExpressionPath(path)) {
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
const normalized = normalizeExpressionPath(path);
|
|
266
|
-
if (!normalized) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
if (!matchesExpressionLocator(normalized, locator)) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
const candidate = toInternalMatch("expression", path);
|
|
273
|
-
if (!candidate) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
if (locator.expectedRange &&
|
|
277
|
-
!matchesRange(path.node.loc, locator.expectedRange)) {
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
match = candidate;
|
|
281
|
-
path.stop();
|
|
282
|
-
},
|
|
283
|
-
MemberExpression(path) {
|
|
284
|
-
const normalized = normalizeExpressionPath(path);
|
|
285
|
-
if (!normalized) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
if (!matchesExpressionLocator(normalized, locator)) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const candidate = toInternalMatch("expression", path);
|
|
292
|
-
if (!candidate) {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
if (locator.expectedRange &&
|
|
296
|
-
!matchesRange(path.node.loc, locator.expectedRange)) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
match = candidate;
|
|
300
|
-
path.stop();
|
|
301
|
-
},
|
|
302
|
-
});
|
|
303
|
-
if (!match) {
|
|
304
|
-
return failLocator("expression", "locator-miss", "Expression not found");
|
|
305
|
-
}
|
|
306
|
-
return { ok: true, match };
|
|
307
|
-
}
|
|
308
|
-
function resolveDirectiveLocator(ast, locator) {
|
|
309
|
-
let match = null;
|
|
310
|
-
traverse(ast, {
|
|
311
|
-
Program(path) {
|
|
312
|
-
const directives = path.get("directives");
|
|
313
|
-
const directivePath = directives.find((directive) => directive.node.value.value === locator.value);
|
|
314
|
-
if (!directivePath) {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
if (locator.expectedRange &&
|
|
318
|
-
!matchesRange(directivePath.node.loc, locator.expectedRange)) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
const candidate = toInternalMatch("directive", directivePath);
|
|
322
|
-
if (!candidate) {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
match = candidate;
|
|
326
|
-
path.stop();
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
if (!match) {
|
|
330
|
-
return failLocator("directive", "locator-miss", `Directive '${locator.value}' not found`);
|
|
331
|
-
}
|
|
332
|
-
return { ok: true, match };
|
|
333
|
-
}
|
|
334
|
-
function resolveExportLocator(ast, locator) {
|
|
335
|
-
let match = null;
|
|
336
|
-
traverse(ast, {
|
|
337
|
-
ExportNamedDeclaration(path) {
|
|
338
|
-
if (locator.exportKind === "generate-metadata") {
|
|
339
|
-
const declaration = path.get("declaration");
|
|
340
|
-
if (declaration.isFunctionDeclaration() &&
|
|
341
|
-
declaration.node.id?.name === "generateMetadata") {
|
|
342
|
-
const candidate = toInternalMatch("export", declaration);
|
|
343
|
-
if (!candidate) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
if (locator.expectedRange &&
|
|
347
|
-
!matchesRange(declaration.node.loc, locator.expectedRange)) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
match = candidate;
|
|
351
|
-
path.stop();
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
if (!declaration.isVariableDeclaration()) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
const declarator = findNamedVariableDeclarator(declaration, "generateMetadata");
|
|
358
|
-
if (!declarator || !declarator.isVariableDeclarator()) {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
const initPath = declarator.get("init");
|
|
362
|
-
if (!initPath.node) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const candidate = toInternalMatch("export", initPath);
|
|
366
|
-
if (!candidate) {
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
if (locator.expectedRange &&
|
|
370
|
-
!matchesRange(initPath.node.loc, locator.expectedRange)) {
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
match = candidate;
|
|
374
|
-
path.stop();
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
const declaration = path.get("declaration");
|
|
378
|
-
if (!declaration.isVariableDeclaration()) {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
const declarator = findNamedVariableDeclarator(declaration, locator.exportKind === "named" ? locator.name : "metadata");
|
|
382
|
-
if (!declarator || !declarator.isVariableDeclarator()) {
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
const initPath = declarator.get("init");
|
|
386
|
-
if (!initPath.node) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
if (locator.expectedRange &&
|
|
390
|
-
!matchesRange(initPath.node.loc, locator.expectedRange)) {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
const candidate = toInternalMatch("export", initPath);
|
|
394
|
-
if (!candidate) {
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
match = candidate;
|
|
398
|
-
path.stop();
|
|
399
|
-
},
|
|
400
|
-
ExportDefaultDeclaration(path) {
|
|
401
|
-
if (locator.exportKind !== "default") {
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
const declaration = path.get("declaration");
|
|
405
|
-
const candidate = toInternalMatch("export", declaration);
|
|
406
|
-
if (!candidate) {
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
if (locator.expectedRange &&
|
|
410
|
-
!matchesRange(declaration.node.loc, locator.expectedRange)) {
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
match = candidate;
|
|
414
|
-
path.stop();
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
if (!match) {
|
|
418
|
-
return failLocator("export", "export-not-found", `Export '${describeExport(locator)}' not found`);
|
|
419
|
-
}
|
|
420
|
-
return { ok: true, match };
|
|
421
|
-
}
|
|
422
|
-
function resolveValueRootPath(ast, locator) {
|
|
423
|
-
let match = null;
|
|
424
|
-
traverse(ast, {
|
|
425
|
-
Expression(path) {
|
|
426
|
-
if (match || locator.root.kind !== "expression") {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
if (!hasExactRange(path.node, locator.root.sourceRange)) {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
const candidate = toInternalMatch("value", path);
|
|
433
|
-
if (!candidate) {
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
match = candidate;
|
|
437
|
-
path.stop();
|
|
438
|
-
},
|
|
439
|
-
VariableDeclarator(path) {
|
|
440
|
-
if (match) {
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
if (locator.root.kind === "binding") {
|
|
444
|
-
if (path.node.id.type !== "Identifier" ||
|
|
445
|
-
path.node.id.name !== locator.root.name) {
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
const initPath = path.get("init");
|
|
449
|
-
if (!initPath.node) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
const candidate = toInternalMatch("value", initPath);
|
|
453
|
-
if (!candidate) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
match = candidate;
|
|
457
|
-
path.stop();
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
if (locator.root.kind !== "hook-state") {
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
const hookStateRoot = locator.root;
|
|
464
|
-
const idPath = path.get("id");
|
|
465
|
-
const initPath = path.get("init");
|
|
466
|
-
if (!idPath.isArrayPattern() || !initPath.isCallExpression()) {
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
const stateIndex = idPath.node.elements.findIndex((element) => element?.type === "Identifier" && element.name === hookStateRoot.name);
|
|
470
|
-
if (stateIndex !== 0) {
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
const callee = initPath.node.callee;
|
|
474
|
-
const hookName = callee.type === "Identifier"
|
|
475
|
-
? callee.name
|
|
476
|
-
: callee.type === "MemberExpression" &&
|
|
477
|
-
callee.property.type === "Identifier"
|
|
478
|
-
? callee.property.name
|
|
479
|
-
: null;
|
|
480
|
-
if (hookName !== hookStateRoot.hook) {
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
const argIndex = hookStateRoot.hook === "useReducer" ? 1 : 0;
|
|
484
|
-
const argPath = path.get(`init.arguments.${argIndex}`);
|
|
485
|
-
if (!argPath || Array.isArray(argPath) || !argPath.node) {
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
const candidate = toInternalMatch("value", argPath);
|
|
489
|
-
if (!candidate) {
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
match = candidate;
|
|
493
|
-
path.stop();
|
|
494
|
-
},
|
|
495
|
-
ExportNamedDeclaration(path) {
|
|
496
|
-
if (match || locator.root.kind !== "named-export") {
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
const declaration = path.get("declaration");
|
|
500
|
-
if (!declaration.isVariableDeclaration()) {
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
const declarator = findNamedVariableDeclarator(declaration, locator.root.name);
|
|
504
|
-
if (!declarator || !declarator.isVariableDeclarator()) {
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const initPath = declarator.get("init");
|
|
508
|
-
if (!initPath.node) {
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const candidate = toInternalMatch("value", initPath);
|
|
512
|
-
if (!candidate) {
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
match = candidate;
|
|
516
|
-
path.stop();
|
|
517
|
-
},
|
|
518
|
-
ExportDefaultDeclaration(path) {
|
|
519
|
-
if (match || locator.root.kind !== "default-export") {
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
const declaration = path.get("declaration");
|
|
523
|
-
const candidate = toInternalMatch("value", declaration);
|
|
524
|
-
if (!candidate) {
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
match = candidate;
|
|
528
|
-
path.stop();
|
|
529
|
-
},
|
|
530
|
-
});
|
|
531
|
-
if (!match)
|
|
532
|
-
return failLocator("value", locator.root.kind === "named-export" ||
|
|
533
|
-
locator.root.kind === "default-export"
|
|
534
|
-
? "export-not-found"
|
|
535
|
-
: locator.root.kind === "expression"
|
|
536
|
-
? "locator-miss"
|
|
537
|
-
: "binding-not-found", "Value root was not found");
|
|
538
|
-
return { ok: true, match };
|
|
539
|
-
}
|
|
540
|
-
function followValuePath(path, segments) {
|
|
541
|
-
let current = unwrapValueAssertion(path);
|
|
542
|
-
for (const segment of segments) {
|
|
543
|
-
current = unwrapValueAssertion(current);
|
|
544
|
-
if (segment.kind === "property") {
|
|
545
|
-
if (!current.isObjectExpression()) {
|
|
546
|
-
return failLocator("value", "unsupported-syntax", "Property path requires object expression");
|
|
547
|
-
}
|
|
548
|
-
const properties = current.get("properties");
|
|
549
|
-
if (properties.some((property) => !property.isObjectProperty())) {
|
|
550
|
-
return failLocator("value", "unsupported-syntax", "Spread properties are not supported");
|
|
551
|
-
}
|
|
552
|
-
const propertyPath = properties.find((property) => matchesObjectPropertyName(property, segment.name));
|
|
553
|
-
if (!propertyPath || !propertyPath.isObjectProperty()) {
|
|
554
|
-
return failLocator("value", "property-not-found", `Property '${segment.name}' not found`);
|
|
555
|
-
}
|
|
556
|
-
current = propertyPath.get("value");
|
|
557
|
-
continue;
|
|
558
|
-
}
|
|
559
|
-
if (!current.isArrayExpression()) {
|
|
560
|
-
return failLocator("value", "unsupported-syntax", "Array index path requires array expression");
|
|
561
|
-
}
|
|
562
|
-
const elements = current.get("elements");
|
|
563
|
-
if (elements.some((element) => element.node?.type === "SpreadElement")) {
|
|
564
|
-
return failLocator("value", "unsupported-syntax", "Spread array elements are not supported");
|
|
565
|
-
}
|
|
566
|
-
const elementPath = elements[segment.index];
|
|
567
|
-
if (!elementPath?.node) {
|
|
568
|
-
return failLocator("value", "array-index-out-of-range", `Array index ${segment.index} is out of range`);
|
|
569
|
-
}
|
|
570
|
-
current = elementPath;
|
|
571
|
-
}
|
|
572
|
-
current = unwrapValueAssertion(current);
|
|
573
|
-
/* node:coverage ignore start */
|
|
574
|
-
const match = toInternalMatch("value", current);
|
|
575
|
-
if (!match) {
|
|
576
|
-
return failLocator("value", "locator-miss", "Resolved value has no source range");
|
|
577
|
-
}
|
|
578
|
-
return { ok: true, match };
|
|
579
|
-
/* node:coverage ignore stop */
|
|
580
|
-
}
|
|
581
|
-
function unwrapValueAssertion(path) {
|
|
582
|
-
let current = path;
|
|
583
|
-
while (current.isTSAsExpression() ||
|
|
584
|
-
current.isTSSatisfiesExpression() ||
|
|
585
|
-
current.isTSNonNullExpression()) {
|
|
586
|
-
current = current.get("expression");
|
|
587
|
-
}
|
|
588
|
-
return current;
|
|
589
|
-
}
|
|
590
|
-
function toInternalMatch(locatorKind, path) {
|
|
591
|
-
const node = path.node;
|
|
592
|
-
if (node.start == null || node.end == null) {
|
|
593
|
-
return null;
|
|
594
|
-
}
|
|
595
|
-
return {
|
|
596
|
-
locatorKind,
|
|
597
|
-
node,
|
|
598
|
-
start: node.start,
|
|
599
|
-
end: node.end,
|
|
600
|
-
path,
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
-
function hasExactRange(node, sourceRange) {
|
|
604
|
-
return matchesRange(node.loc, sourceRange);
|
|
605
|
-
}
|
|
606
|
-
function matchesRange(loc, range) {
|
|
607
|
-
if (!loc) {
|
|
608
|
-
return false;
|
|
609
|
-
}
|
|
610
|
-
return (loc.start.line === range.startLine &&
|
|
611
|
-
loc.start.column === range.startColumn &&
|
|
612
|
-
loc.end.line === range.endLine &&
|
|
613
|
-
loc.end.column === range.endColumn);
|
|
614
|
-
}
|
|
615
|
-
function computeJsxStructuralPath(path) {
|
|
616
|
-
const segments = [];
|
|
617
|
-
let current = path;
|
|
618
|
-
const targetNode = path.node;
|
|
619
|
-
while (current) {
|
|
620
|
-
if (current.isJSXElement()) {
|
|
621
|
-
const tagName = getJsxTagName(current.node.openingElement);
|
|
622
|
-
if (tagName) {
|
|
623
|
-
if (/^[A-Z]/.test(tagName)) {
|
|
624
|
-
segments.unshift(`component:${tagName}#${computeSiblingOrdinal(current, tagName)}`);
|
|
625
|
-
}
|
|
626
|
-
else {
|
|
627
|
-
segments.unshift(`${tagName}#${computeSiblingOrdinal(current, tagName)}`);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
else if (current.isJSXFragment() && current.node === targetNode) {
|
|
632
|
-
segments.unshift("fragment");
|
|
633
|
-
}
|
|
634
|
-
if (!current.parentPath || isComponentBoundary(current.parentPath))
|
|
635
|
-
break;
|
|
636
|
-
current = current.parentPath;
|
|
637
|
-
}
|
|
638
|
-
return segments.join("/");
|
|
639
|
-
}
|
|
640
|
-
function computeSiblingOrdinal(path, tagName) {
|
|
641
|
-
const owner = findStructuralParent(path);
|
|
642
|
-
if (!owner) {
|
|
643
|
-
return 0;
|
|
644
|
-
}
|
|
645
|
-
const cached = siblingOrdinalCache
|
|
646
|
-
.get(owner.node)
|
|
647
|
-
?.get(tagName)
|
|
648
|
-
?.get(path.node);
|
|
649
|
-
if (cached !== undefined) {
|
|
650
|
-
return cached;
|
|
651
|
-
}
|
|
652
|
-
let ordinal = 0;
|
|
653
|
-
let tagOrdinals = siblingOrdinalCache.get(owner.node)?.get(tagName);
|
|
654
|
-
if (!tagOrdinals) {
|
|
655
|
-
let containerCache = siblingOrdinalCache.get(owner.node);
|
|
656
|
-
if (!containerCache) {
|
|
657
|
-
containerCache = new Map();
|
|
658
|
-
siblingOrdinalCache.set(owner.node, containerCache);
|
|
659
|
-
}
|
|
660
|
-
tagOrdinals = new WeakMap();
|
|
661
|
-
containerCache.set(tagName, tagOrdinals);
|
|
662
|
-
}
|
|
663
|
-
for (const sibling of collectStructuralChildren(owner)) {
|
|
664
|
-
if (getJsxTagName(sibling.node.openingElement) === tagName) {
|
|
665
|
-
tagOrdinals.set(sibling.node, ordinal);
|
|
666
|
-
if (sibling.node === path.node) {
|
|
667
|
-
return ordinal;
|
|
668
|
-
}
|
|
669
|
-
ordinal++;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
return tagOrdinals.get(path.node) ?? 0;
|
|
673
|
-
}
|
|
674
|
-
function findStructuralParent(path) {
|
|
675
|
-
let current = path.parentPath;
|
|
676
|
-
let fragmentOwner = null;
|
|
677
|
-
while (current) {
|
|
678
|
-
if (current.isJSXFragment()) {
|
|
679
|
-
fragmentOwner = current;
|
|
680
|
-
current = current.parentPath;
|
|
681
|
-
continue;
|
|
682
|
-
}
|
|
683
|
-
if (current.isJSXElement()) {
|
|
684
|
-
return current;
|
|
685
|
-
}
|
|
686
|
-
current = current.parentPath;
|
|
687
|
-
}
|
|
688
|
-
return fragmentOwner;
|
|
689
|
-
}
|
|
690
|
-
function collectStructuralChildren(owner) {
|
|
691
|
-
const cached = structuralChildrenCache.get(owner.node);
|
|
692
|
-
if (cached) {
|
|
693
|
-
return cached;
|
|
694
|
-
}
|
|
695
|
-
const structuralChildren = [];
|
|
696
|
-
const children = owner.get("children");
|
|
697
|
-
for (const child of children) {
|
|
698
|
-
if (Array.isArray(child)) {
|
|
699
|
-
continue;
|
|
700
|
-
}
|
|
701
|
-
if (child.isJSXElement()) {
|
|
702
|
-
structuralChildren.push(child);
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
if (child.isJSXFragment()) {
|
|
706
|
-
structuralChildren.push(...collectStructuralChildren(child));
|
|
707
|
-
continue;
|
|
708
|
-
}
|
|
709
|
-
if (child.isJSXExpressionContainer()) {
|
|
710
|
-
structuralChildren.push(...collectExpressionStructuralChildren(child.get("expression")));
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
structuralChildrenCache.set(owner.node, structuralChildren);
|
|
714
|
-
return structuralChildren;
|
|
715
|
-
}
|
|
716
|
-
function collectExpressionStructuralChildren(expression) {
|
|
717
|
-
if (expression.isJSXElement()) {
|
|
718
|
-
return [expression];
|
|
719
|
-
}
|
|
720
|
-
if (expression.isJSXFragment()) {
|
|
721
|
-
return collectStructuralChildren(expression);
|
|
722
|
-
}
|
|
723
|
-
if (expression.isParenthesizedExpression()) {
|
|
724
|
-
return collectExpressionStructuralChildren(expression.get("expression"));
|
|
725
|
-
}
|
|
726
|
-
if (expression.isLogicalExpression() && expression.node.operator === "&&") {
|
|
727
|
-
return collectExpressionStructuralChildren(expression.get("right"));
|
|
728
|
-
}
|
|
729
|
-
if (expression.isConditionalExpression()) {
|
|
730
|
-
return [
|
|
731
|
-
...collectExpressionStructuralChildren(expression.get("consequent")),
|
|
732
|
-
...collectExpressionStructuralChildren(expression.get("alternate")),
|
|
733
|
-
];
|
|
734
|
-
}
|
|
735
|
-
if (expression.isArrayExpression()) {
|
|
736
|
-
return expression.get("elements").flatMap((element) => {
|
|
737
|
-
if (Array.isArray(element) || !element.node || !element.isExpression()) {
|
|
738
|
-
return [];
|
|
739
|
-
}
|
|
740
|
-
return collectExpressionStructuralChildren(element);
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
return [];
|
|
744
|
-
}
|
|
745
|
-
function getJsxTagName(openingElement) {
|
|
746
|
-
if (openingElement.name.type === "JSXIdentifier") {
|
|
747
|
-
return openingElement.name.name;
|
|
748
|
-
}
|
|
749
|
-
if (openingElement.name.type === "JSXMemberExpression") {
|
|
750
|
-
return flattenJsxMemberExpression(openingElement.name);
|
|
751
|
-
}
|
|
752
|
-
return null;
|
|
753
|
-
}
|
|
754
|
-
function flattenJsxMemberExpression(expression) {
|
|
755
|
-
const parts = [];
|
|
756
|
-
let current = expression;
|
|
757
|
-
while (current.type === "JSXMemberExpression") {
|
|
758
|
-
parts.unshift(current.property.name);
|
|
759
|
-
current = current.object;
|
|
760
|
-
}
|
|
761
|
-
parts.unshift(current.name);
|
|
762
|
-
return parts.join(".");
|
|
763
|
-
}
|
|
764
|
-
function getEnclosingComponentName(path) {
|
|
765
|
-
let current = path;
|
|
766
|
-
while (current) {
|
|
767
|
-
if (current.isFunctionDeclaration()) {
|
|
768
|
-
return current.node.id?.name ?? null;
|
|
769
|
-
}
|
|
770
|
-
if ((current.isArrowFunctionExpression() || current.isFunctionExpression()) &&
|
|
771
|
-
current.parentPath?.isVariableDeclarator()) {
|
|
772
|
-
const id = current.parentPath.node.id;
|
|
773
|
-
return id.type === "Identifier" ? id.name : null;
|
|
774
|
-
}
|
|
775
|
-
current = current.parentPath;
|
|
776
|
-
}
|
|
777
|
-
return null;
|
|
778
|
-
}
|
|
779
|
-
function isComponentBoundary(path) {
|
|
780
|
-
if (path.isFunctionDeclaration() ||
|
|
781
|
-
path.isFunctionExpression() ||
|
|
782
|
-
path.isArrowFunctionExpression()) {
|
|
783
|
-
return true;
|
|
784
|
-
}
|
|
785
|
-
return false;
|
|
786
|
-
}
|
|
787
|
-
function isExpressionPath(path) {
|
|
788
|
-
if (!path.isExpression()) {
|
|
789
|
-
return false;
|
|
790
|
-
}
|
|
791
|
-
if (path.parentPath?.isMemberExpression({ property: path.node })) {
|
|
792
|
-
return false;
|
|
793
|
-
}
|
|
794
|
-
return true;
|
|
795
|
-
}
|
|
796
|
-
function normalizeExpressionPath(path) {
|
|
797
|
-
if (path.isIdentifier()) {
|
|
798
|
-
return {
|
|
799
|
-
base: path.node.name,
|
|
800
|
-
path: [],
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
if (!path.isMemberExpression()) {
|
|
804
|
-
return null;
|
|
805
|
-
}
|
|
806
|
-
const segments = [];
|
|
807
|
-
let current = path.node;
|
|
808
|
-
while (current.type === "MemberExpression") {
|
|
809
|
-
if (current.computed) {
|
|
810
|
-
if (current.property.type === "NumericLiteral") {
|
|
811
|
-
segments.unshift({ kind: "index", index: current.property.value });
|
|
812
|
-
}
|
|
813
|
-
else if (current.property.type === "StringLiteral") {
|
|
814
|
-
segments.unshift({ kind: "property", name: current.property.value });
|
|
815
|
-
}
|
|
816
|
-
else {
|
|
817
|
-
return null;
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
else if (current.property.type === "Identifier") {
|
|
821
|
-
segments.unshift({ kind: "property", name: current.property.name });
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
return null;
|
|
825
|
-
}
|
|
826
|
-
if (current.object.type === "Identifier") {
|
|
827
|
-
return {
|
|
828
|
-
base: current.object.name,
|
|
829
|
-
path: segments,
|
|
830
|
-
};
|
|
831
|
-
}
|
|
832
|
-
if (current.object.type !== "MemberExpression") {
|
|
833
|
-
return null;
|
|
834
|
-
}
|
|
835
|
-
current = current.object;
|
|
836
|
-
}
|
|
837
|
-
return null;
|
|
838
|
-
}
|
|
839
|
-
function matchesExpressionLocator(expression, locator) {
|
|
840
|
-
return (expression.base === locator.base &&
|
|
841
|
-
sameValuePath(expression.path, locator.path ?? []));
|
|
842
|
-
}
|
|
843
|
-
function sameValuePath(left, right) {
|
|
844
|
-
if (left.length !== right.length) {
|
|
845
|
-
return false;
|
|
846
|
-
}
|
|
847
|
-
for (let index = 0; index < left.length; index += 1) {
|
|
848
|
-
const leftSegment = left[index];
|
|
849
|
-
const rightSegment = right[index];
|
|
850
|
-
if (leftSegment.kind !== rightSegment.kind) {
|
|
851
|
-
return false;
|
|
852
|
-
}
|
|
853
|
-
if (leftSegment.kind === "property") {
|
|
854
|
-
if (rightSegment.kind !== "property" ||
|
|
855
|
-
leftSegment.name !== rightSegment.name) {
|
|
856
|
-
return false;
|
|
857
|
-
}
|
|
858
|
-
continue;
|
|
859
|
-
}
|
|
860
|
-
if (rightSegment.kind !== "index" ||
|
|
861
|
-
leftSegment.index !== rightSegment.index) {
|
|
862
|
-
return false;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
867
|
-
function getObjectPropertyKey(node) {
|
|
868
|
-
if (node.key.type === "Identifier") {
|
|
869
|
-
return node.key.name;
|
|
870
|
-
}
|
|
871
|
-
if (node.key.type === "StringLiteral") {
|
|
872
|
-
return node.key.value;
|
|
873
|
-
}
|
|
874
|
-
return null;
|
|
875
|
-
}
|
|
876
|
-
function describeExport(locator) {
|
|
877
|
-
if (locator.exportKind === "named") {
|
|
878
|
-
return locator.name;
|
|
879
|
-
}
|
|
880
|
-
return locator.exportKind;
|
|
881
|
-
}
|
|
882
|
-
function failLocator(locatorKind, code, message, details) {
|
|
883
|
-
return {
|
|
884
|
-
ok: false,
|
|
885
|
-
diagnostic: createDiagnostic(code, message, locatorKind, details),
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
function matchesExpectedJsxIdentity(path, expectedIdentity) {
|
|
889
|
-
const component = getEnclosingComponentName(path);
|
|
890
|
-
if (component !== expectedIdentity.component) {
|
|
891
|
-
return false;
|
|
892
|
-
}
|
|
893
|
-
return computeJsxStructuralPath(path) === expectedIdentity.structuralPath;
|
|
894
|
-
}
|
|
895
|
-
function isNamedJsxAttributePath(attribute, name) {
|
|
896
|
-
if (!attribute.isJSXAttribute()) {
|
|
897
|
-
return false;
|
|
898
|
-
}
|
|
899
|
-
if (attribute.node.name.type !== "JSXIdentifier") {
|
|
900
|
-
return false;
|
|
901
|
-
}
|
|
902
|
-
return attribute.node.name.name === name;
|
|
903
|
-
}
|
|
904
|
-
function findNamedVariableDeclarator(declaration, name) {
|
|
905
|
-
return declaration.get("declarations").find((item) => {
|
|
906
|
-
if (!item.isVariableDeclarator()) {
|
|
907
|
-
return false;
|
|
908
|
-
}
|
|
909
|
-
if (item.node.id.type !== "Identifier") {
|
|
910
|
-
return false;
|
|
911
|
-
}
|
|
912
|
-
return item.node.id.name === name;
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
function matchesObjectPropertyName(property, name) {
|
|
916
|
-
if (!property.isObjectProperty()) {
|
|
917
|
-
return false;
|
|
918
|
-
}
|
|
919
|
-
return getObjectPropertyKey(property.node) === name;
|
|
920
|
-
}
|