@shapeshift-labs/frontier-lang-compiler 0.2.103 → 0.2.105
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/README.md +14 -0
- package/dist/declarations/bidirectional-target-change-source-edit.d.ts +30 -0
- package/dist/declarations/bidirectional-target-change.d.ts +10 -0
- package/dist/declarations/js-ts-safe-member-merge.d.ts +86 -0
- package/dist/declarations/js-ts-safe-merge.d.ts +131 -0
- package/dist/declarations/js-ts-semantic-conflict-sidecars.d.ts +235 -0
- package/dist/declarations/js-ts-semantic-merge-contracts.d.ts +287 -0
- package/dist/declarations/js-ts-semantic-merge.d.ts +4 -0
- package/dist/declarations/native-import-losses.d.ts +3 -0
- package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
- package/dist/declarations/semantic-edit-script.d.ts +7 -4
- package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
- package/dist/declarations/semantic-patch-bundle.d.ts +6 -4
- package/dist/declarations/semantic-sidecar-example.d.ts +18 -0
- package/dist/declarations/semantic-transform-identity.d.ts +3 -0
- package/dist/declarations/source-preservation.d.ts +72 -0
- package/dist/declarations/universal-capability.d.ts +4 -0
- package/dist/declarations/universal-conversion-artifacts.d.ts +61 -1
- package/dist/declarations/universal-conversion-compact-counts.d.ts +51 -0
- package/dist/declarations/universal-conversion-plan.d.ts +6 -1
- package/dist/declarations/universal-representation-coverage.d.ts +90 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/internal/index-impl/bidirectionalExactSourceBackprojection.js +199 -0
- package/dist/internal/index-impl/bidirectionalSameLanguageSourceProjection.js +112 -0
- package/dist/internal/index-impl/bidirectionalSourceEditProjection.js +319 -0
- package/dist/internal/index-impl/bidirectionalSourceEditProjectionArtifacts.js +67 -0
- package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +17 -5
- package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +58 -20
- package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +60 -7
- package/dist/internal/index-impl/createLightweightNativeImport.js +1 -0
- package/dist/internal/index-impl/createNativeSourcePreservation.js +28 -2
- package/dist/internal/index-impl/diffNativeSymbols.js +3 -3
- package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +43 -8
- package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
- package/dist/internal/index-impl/replaySemanticEditProjection.js +39 -19
- package/dist/internal/index-impl/semanticEditBundleAdmission.js +7 -3
- package/dist/internal/index-impl/semanticEditBundleIndex.js +47 -1
- package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +40 -0
- package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
- package/dist/internal/index-impl/semanticEditProjectionRecord.js +29 -0
- package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +39 -0
- package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +85 -0
- package/dist/internal/index-impl/semanticEditScripts.js +4 -0
- package/dist/internal/index-impl/semanticEditSourceRanges.js +27 -0
- package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
- package/dist/internal/index-impl/semanticPatchBundleAdmission.js +41 -7
- package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -0
- package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +2 -0
- package/dist/internal/index-impl/semanticSidecarQuality.js +111 -0
- package/dist/internal/index-impl/semanticSourceEditDedupe.js +69 -9
- package/dist/internal/index-impl/semanticTransformIdentityRecords.js +85 -9
- package/dist/js-ts-safe-member-merge-result.js +158 -0
- package/dist/js-ts-safe-member-merge.js +265 -0
- package/dist/js-ts-safe-merge-analyze.js +279 -0
- package/dist/js-ts-safe-merge-composed.js +170 -0
- package/dist/js-ts-safe-merge-constants.js +50 -0
- package/dist/js-ts-safe-merge-context.js +118 -0
- package/dist/js-ts-safe-merge-ledger-validation.js +92 -0
- package/dist/js-ts-safe-merge-ledger.js +85 -0
- package/dist/js-ts-safe-merge-parse-declarations.js +210 -0
- package/dist/js-ts-safe-merge-parse-statements.js +155 -0
- package/dist/js-ts-safe-merge-plan.js +190 -0
- package/dist/js-ts-safe-merge.js +175 -0
- package/dist/js-ts-semantic-conflict-sidecar-constants.js +77 -0
- package/dist/js-ts-semantic-conflict-sidecar-detectors.js +195 -0
- package/dist/js-ts-semantic-conflict-sidecar-normalize.js +203 -0
- package/dist/js-ts-semantic-conflict-sidecar-utils.js +190 -0
- package/dist/js-ts-semantic-conflict-sidecars.js +81 -0
- package/dist/js-ts-semantic-merge-contract-helpers.js +128 -0
- package/dist/js-ts-semantic-merge-contracts.js +217 -0
- package/dist/js-ts-semantic-merge-member-containers.js +100 -0
- package/dist/js-ts-semantic-merge-member-keys.js +142 -0
- package/dist/js-ts-semantic-merge-member-segments.js +185 -0
- package/dist/js-ts-semantic-merge-member-source.js +82 -0
- package/dist/js-ts-semantic-merge-member-utils.js +18 -0
- package/dist/js-ts-semantic-merge-parse.js +16 -0
- package/dist/js-ts-semantic-merge.js +24 -0
- package/dist/lightweight-dependency-effects.js +51 -0
- package/dist/lightweight-dependency-language.js +12 -1
- package/dist/lightweight-dependency-relations.js +14 -27
- package/dist/native-region-scanner-core.js +33 -1
- package/dist/native-region-scanner-csharp.js +151 -0
- package/dist/native-region-scanner-dart.js +91 -0
- package/dist/native-region-scanner-dynamic.js +21 -151
- package/dist/native-region-scanner-functional.js +40 -13
- package/dist/native-region-scanner-java.js +97 -0
- package/dist/native-region-scanner-js-class.js +100 -0
- package/dist/native-region-scanner-js-helpers.js +28 -86
- package/dist/native-region-scanner-js-imports.js +121 -1
- package/dist/native-region-scanner-js-nested.js +96 -8
- package/dist/native-region-scanner-js-structure.js +27 -0
- package/dist/native-region-scanner-js-types.js +99 -0
- package/dist/native-region-scanner-js.js +70 -118
- package/dist/native-region-scanner-kotlin.js +94 -0
- package/dist/native-region-scanner-main.js +15 -181
- package/dist/native-region-scanner-php.js +80 -0
- package/dist/native-region-scanner-python.js +62 -0
- package/dist/native-region-scanner-ruby.js +72 -0
- package/dist/native-region-scanner-scala.js +91 -0
- package/dist/native-region-scanner-spans.js +74 -0
- package/dist/native-region-scanner-swift.js +155 -0
- package/dist/native-region-scanner.js +14 -10
- package/dist/native-source-ledger-helpers.js +195 -0
- package/dist/native-source-ledger.js +306 -0
- package/dist/native-source-preservation-scanner.js +4 -0
- package/dist/semantic-import-callsite-regions.js +136 -0
- package/dist/semantic-import-effect-regions.js +283 -0
- package/dist/semantic-import-regions.js +11 -2
- package/dist/semantic-import-sidecar-entry.js +16 -2
- package/dist/semantic-import-sidecar-types.d.ts +2 -0
- package/dist/semantic-sidecar-example.js +68 -0
- package/dist/universal-capability-matrix.js +23 -0
- package/dist/universal-conversion-artifact-query.js +79 -2
- package/dist/universal-conversion-artifact-semantic-edit.js +103 -0
- package/dist/universal-conversion-artifact-summary.js +33 -1
- package/dist/universal-conversion-artifacts.js +13 -48
- package/dist/universal-conversion-plan-scoring.js +21 -1
- package/dist/universal-conversion-plan-summary.js +30 -0
- package/dist/universal-conversion-plan.js +25 -9
- package/dist/universal-conversion-route-metadata.js +96 -0
- package/dist/universal-conversion-route-operations.js +7 -0
- package/dist/universal-representation-coverage.js +193 -0
- package/package.json +1 -1
|
@@ -6,17 +6,19 @@ import {
|
|
|
6
6
|
sourceLines,
|
|
7
7
|
splitParameters
|
|
8
8
|
} from './native-region-scanner-core.js';
|
|
9
|
+
import { braceBlockSpan, endKeywordBlockSpan, pythonBlockSpan, terminatedBlockSpan } from './native-region-scanner-spans.js';
|
|
9
10
|
|
|
10
11
|
function scanElixir(input) {
|
|
11
12
|
const declarations = [];
|
|
12
13
|
let currentModule;
|
|
13
|
-
|
|
14
|
+
const lines = sourceLines(input.sourceText);
|
|
15
|
+
for (const [index, { line, number }] of lines.entries()) {
|
|
14
16
|
const trimmed = line.trim();
|
|
15
17
|
let match;
|
|
16
18
|
let recordedMeta = false;
|
|
17
19
|
if ((match = trimmed.match(/^defmodule\s+([A-Z]\w*(?:\.[A-Z]\w*)*)\s+do\b/))) {
|
|
18
20
|
currentModule = match[1];
|
|
19
|
-
declarations.push(nativeDeclaration(input, number, 'ModuleDefinition', 'module', match[1], {}, true));
|
|
21
|
+
declarations.push(nativeDeclaration(input, number, 'ModuleDefinition', 'module', match[1], {}, true, endSpanOptions(input, lines, index)));
|
|
20
22
|
} else if ((match = trimmed.match(/^(?:alias|import|require)\s+([A-Z]\w*(?:\.[A-Z]\w*)*)/))) {
|
|
21
23
|
declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDirective', 'module'));
|
|
22
24
|
} else if ((match = trimmed.match(/^use\s+([A-Z]\w*(?:\.[A-Z]\w*)*)/))) {
|
|
@@ -26,7 +28,8 @@ function scanElixir(input) {
|
|
|
26
28
|
declarations.push(nativeMacroLoss(input, number, trimmed, 'macroExpansion', match[2]));
|
|
27
29
|
recordedMeta = true;
|
|
28
30
|
} else if ((match = trimmed.match(/^defp?\s+([A-Za-z_]\w*[!?]?)\s*(?:\(([^)]*)\)|([^,]*))?/))) {
|
|
29
|
-
|
|
31
|
+
const hasDoBlock = /\bdo\b/.test(trimmed);
|
|
32
|
+
declarations.push(nativeDeclaration(input, number, 'FunctionDefinition', 'function', match[1], { parameters: splitParameters(match[2] ?? match[3]) }, hasDoBlock, hasDoBlock ? endSpanOptions(input, lines, index) : {}));
|
|
30
33
|
} else if (trimmed.startsWith('defstruct')) {
|
|
31
34
|
declarations.push(nativeDeclaration(input, number, 'StructDefinition', 'type', currentModule ?? `struct_${number}`, {}, true));
|
|
32
35
|
} else if ((match = trimmed.match(/^@(type|typep|opaque|callback)\s+([A-Za-z_]\w*[!?]?)/))) {
|
|
@@ -39,10 +42,19 @@ function scanElixir(input) {
|
|
|
39
42
|
return declarations;
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
function endSpanOptions(input, lines, index) {
|
|
46
|
+
return { span: endKeywordBlockSpan(input, lines, index) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function braceSpanOptions(input, lines, index, hasBraceBody) {
|
|
50
|
+
return hasBraceBody ? { span: braceBlockSpan(input, lines, index) } : {};
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
function scanErlang(input) {
|
|
43
54
|
const declarations = [];
|
|
44
55
|
const seenFunctions = new Set();
|
|
45
|
-
|
|
56
|
+
const lines = sourceLines(input.sourceText);
|
|
57
|
+
for (const [index, { line, number }] of lines.entries()) {
|
|
46
58
|
const trimmed = line.trim();
|
|
47
59
|
let match;
|
|
48
60
|
let recordedMacro = false;
|
|
@@ -70,7 +82,7 @@ function scanErlang(input) {
|
|
|
70
82
|
const name = erlangAtomName(match[1]);
|
|
71
83
|
if (!seenFunctions.has(name)) {
|
|
72
84
|
seenFunctions.add(name);
|
|
73
|
-
declarations.push(nativeDeclaration(input, number, 'FunctionClause', 'function', name, { parameters: splitParameters(match[2]) }, true));
|
|
85
|
+
declarations.push(nativeDeclaration(input, number, 'FunctionClause', 'function', name, { parameters: splitParameters(match[2]) }, true, { span: terminatedBlockSpan(input, lines, index, /\.\s*$/) }));
|
|
74
86
|
}
|
|
75
87
|
}
|
|
76
88
|
if (!recordedMacro && /(^|[^A-Za-z0-9_])\?[A-Za-z_]\w*/.test(trimmed)) {
|
|
@@ -83,7 +95,8 @@ function scanErlang(input) {
|
|
|
83
95
|
function scanHaskell(input) {
|
|
84
96
|
const declarations = [];
|
|
85
97
|
const seenFunctions = new Set();
|
|
86
|
-
|
|
98
|
+
const lines = sourceLines(input.sourceText);
|
|
99
|
+
for (const [index, { line, number }] of lines.entries()) {
|
|
87
100
|
const trimmed = line.trim();
|
|
88
101
|
let match;
|
|
89
102
|
if (/^#\s*(?:if|ifdef|ifndef|else|elif|endif|define|include)\b/.test(trimmed)) {
|
|
@@ -106,12 +119,15 @@ function scanHaskell(input) {
|
|
|
106
119
|
} else if ((match = trimmed.match(/^class\s+(?:\([^)]*\)\s*=>\s*)?([A-Z][A-Za-z0-9_']*)\b/))) {
|
|
107
120
|
declarations.push(nativeDeclaration(input, number, 'ClassDeclaration', 'type', match[1], {}, /\bwhere\b/.test(trimmed)));
|
|
108
121
|
} else if ((match = trimmed.match(/^([a-z_][A-Za-z0-9_']*)\s*::\s*(.+)$/))) {
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
declarations.push(nativeDeclaration(input, number, 'FunctionSignature', 'function', match[1], { signature: match[2].trim() }, false, {
|
|
123
|
+
regionKind: 'declaration',
|
|
124
|
+
symbolId: `symbol:${input.language}:signature:${idFragment(match[1])}`,
|
|
125
|
+
metadata: { signatureOnly: true }
|
|
126
|
+
}));
|
|
111
127
|
} else if ((match = trimmed.match(/^([a-z_][A-Za-z0-9_']*)\b[^=]*=/))) {
|
|
112
128
|
if (!seenFunctions.has(match[1])) {
|
|
113
129
|
seenFunctions.add(match[1]);
|
|
114
|
-
declarations.push(nativeDeclaration(input, number, 'FunctionBinding', 'function', match[1], {}, true));
|
|
130
|
+
declarations.push(nativeDeclaration(input, number, 'FunctionBinding', 'function', match[1], {}, true, { span: pythonBlockSpan(input, lines, index) }));
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
133
|
}
|
|
@@ -120,7 +136,8 @@ function scanHaskell(input) {
|
|
|
120
136
|
|
|
121
137
|
function scanR(input) {
|
|
122
138
|
const declarations = [];
|
|
123
|
-
|
|
139
|
+
const lines = sourceLines(input.sourceText);
|
|
140
|
+
for (const [index, { line, number }] of lines.entries()) {
|
|
124
141
|
const trimmed = line.trim();
|
|
125
142
|
let match;
|
|
126
143
|
if ((match = trimmed.match(/^(?:library|require)\s*\(\s*["']?([A-Za-z_][\w.-]*)["']?/))) {
|
|
@@ -130,7 +147,7 @@ function scanR(input) {
|
|
|
130
147
|
} else if ((match = trimmed.match(/^source\s*\(\s*["']([^"']+)["']/))) {
|
|
131
148
|
declarations.push(nativeImportDeclaration(input, number, match[1], 'SourceCall', 'module'));
|
|
132
149
|
} else if ((match = trimmed.match(/^([A-Za-z_][\w.]*)\s*(?:<-|=)\s*function\s*\(([^)]*)\)/))) {
|
|
133
|
-
declarations.push(nativeDeclaration(input, number, 'FunctionAssignment', 'function', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{')));
|
|
150
|
+
declarations.push(nativeDeclaration(input, number, 'FunctionAssignment', 'function', match[1], { parameters: splitParameters(match[2]) }, trimmed.includes('{'), braceSpanOptions(input, lines, index, trimmed.includes('{'))));
|
|
134
151
|
} else if ((match = trimmed.match(/^([A-Za-z_][\w.]*)\s*<-\s*R6Class\s*\(\s*["']([^"']+)["']/))) {
|
|
135
152
|
declarations.push(nativeDeclaration(input, number, 'R6ClassDeclaration', 'class', match[2] || match[1], { binding: match[1] }, true));
|
|
136
153
|
declarations.push(nativeMacroLoss(input, number, trimmed, 'dynamicRuntime', match[2] || match[1]));
|
|
@@ -154,9 +171,19 @@ function scanR(input) {
|
|
|
154
171
|
}
|
|
155
172
|
|
|
156
173
|
function scanGenericDeclarations(input) {
|
|
157
|
-
|
|
174
|
+
const lines = sourceLines(input.sourceText);
|
|
175
|
+
return lines
|
|
176
|
+
.map(({ line, number }, index) => ({ line, number, index }))
|
|
158
177
|
.filter(({ line }) => /\b(function|class|struct|enum|trait|interface|def)\b/.test(line))
|
|
159
|
-
.map(({ line, number }) => nativeDeclaration(input, number, 'NativeDeclaration', 'variable', idFragment(line.trim()).slice(0, 40), { source: line.trim() }, true));
|
|
178
|
+
.map(({ line, number, index }) => nativeDeclaration(input, number, 'NativeDeclaration', 'variable', idFragment(line.trim()).slice(0, 40), { source: line.trim() }, true, genericSpanOptions(input, lines, index)));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function genericSpanOptions(input, lines, index) {
|
|
182
|
+
const line = lines[index]?.line.trim() ?? '';
|
|
183
|
+
if (line.includes('{')) return { span: braceBlockSpan(input, lines, index) };
|
|
184
|
+
if (/\b(?:class|module|def|function)\b/.test(line)) return { span: endKeywordBlockSpan(input, lines, index) };
|
|
185
|
+
if (/:\s*$/.test(line)) return { span: pythonBlockSpan(input, lines, index) };
|
|
186
|
+
return {};
|
|
160
187
|
}
|
|
161
188
|
|
|
162
189
|
function elixirMetaName(source) {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { upperFirst } from './native-import-utils.js';
|
|
2
|
+
import { nativeDeclaration, nativeImportDeclaration, sourceLines, splitParameters, splitTypeParameters } from './native-region-scanner-core.js';
|
|
3
|
+
import { braceBlockSpan } from './native-region-scanner-spans.js';
|
|
4
|
+
|
|
5
|
+
function scanJava(input) {
|
|
6
|
+
const declarations = [];
|
|
7
|
+
const blockStack = [];
|
|
8
|
+
const lines = sourceLines(input.sourceText);
|
|
9
|
+
let braceDepth = 0;
|
|
10
|
+
for (const [index, { line, number }] of lines.entries()) {
|
|
11
|
+
const trimmed = line.trim();
|
|
12
|
+
const lineStartDepth = depthAfterLeadingClosers(trimmed, braceDepth);
|
|
13
|
+
while (blockStack.length && blockStack[blockStack.length - 1].bodyDepth > lineStartDepth) blockStack.pop();
|
|
14
|
+
|
|
15
|
+
let match;
|
|
16
|
+
if ((match = trimmed.match(/^package\s+([A-Za-z_][\w.]*);/))) {
|
|
17
|
+
declarations.push(nativeDeclaration(input, number, 'PackageDeclaration', 'package', match[1], {}, false));
|
|
18
|
+
} else if ((match = trimmed.match(/^import\s+(?:static\s+)?([A-Za-z_][\w.*]*);/))) {
|
|
19
|
+
declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDeclaration', 'package'));
|
|
20
|
+
} else if ((match = trimmed.match(/^((?:(?:public|protected|private|abstract|final|static|sealed|non-sealed)\s+)*)(class|interface|enum|record|@interface)\s+([A-Za-z_$][\w$]*)/))) {
|
|
21
|
+
const owner = nearestType(blockStack);
|
|
22
|
+
const name = owner ? `${owner.name}.${match[3]}` : match[3];
|
|
23
|
+
const kind = match[2] === '@interface' ? 'AnnotationDeclaration' : `${upperFirst(match[2])}Declaration`;
|
|
24
|
+
const hasBody = trimmed.includes('{');
|
|
25
|
+
declarations.push(nativeDeclaration(input, number, kind, javaSymbolKind(match[2]), name, {
|
|
26
|
+
modifiers: javaModifiers(match[1]),
|
|
27
|
+
...(owner ? { owner: owner.name } : {})
|
|
28
|
+
}, hasBody, spanOptions(input, lines, index, hasBody)));
|
|
29
|
+
if (hasBody) blockStack.push({ kind: javaTypeStackKind(match[2]), name, bodyDepth: braceDepth + 1 });
|
|
30
|
+
} else if ((match = trimmed.match(/^((?:(?:public|protected|private|abstract|final|static|synchronized|native)\s+)*)(?:<([^>]+)>\s+)?[A-Za-z_$][\w$<>\[\].?,\s]*\s+([A-Za-z_$][\w$]*)\s*\(([^)]*)\)\s*(?:throws\s+[^{]+)?(?:\{.*|;)?$/))) {
|
|
31
|
+
const owner = nearestType(blockStack);
|
|
32
|
+
const target = javaMethodTarget(owner, match[1], match[3]);
|
|
33
|
+
const hasBody = trimmed.includes('{');
|
|
34
|
+
declarations.push(nativeDeclaration(input, number, 'MethodDeclaration', target.owner ? 'method' : 'function', target.name, {
|
|
35
|
+
methodName: match[3],
|
|
36
|
+
modifiers: javaModifiers(match[1]),
|
|
37
|
+
typeParameters: splitTypeParameters(match[2]),
|
|
38
|
+
parameters: splitParameters(match[4]),
|
|
39
|
+
...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {})
|
|
40
|
+
}, hasBody, {
|
|
41
|
+
...spanOptions(input, lines, index, hasBody),
|
|
42
|
+
metadata: {
|
|
43
|
+
methodName: match[3],
|
|
44
|
+
modifiers: javaModifiers(match[1]),
|
|
45
|
+
...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {})
|
|
46
|
+
}
|
|
47
|
+
}));
|
|
48
|
+
if (hasBody) blockStack.push({ kind: 'method', name: target.name, bodyDepth: braceDepth + 1 });
|
|
49
|
+
}
|
|
50
|
+
braceDepth = Math.max(0, braceDepth + braceDelta(line));
|
|
51
|
+
}
|
|
52
|
+
return declarations;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function spanOptions(input, lines, index, hasBraceBody) {
|
|
56
|
+
return hasBraceBody ? { span: braceBlockSpan(input, lines, index) } : {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function depthAfterLeadingClosers(trimmed, depth) {
|
|
60
|
+
const closers = String(trimmed).match(/^}+/)?.[0].length ?? 0;
|
|
61
|
+
return Math.max(0, depth - closers);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function nearestType(blockStack) {
|
|
65
|
+
for (let index = blockStack.length - 1; index >= 0; index -= 1) {
|
|
66
|
+
if (blockStack[index].kind === 'method') return undefined;
|
|
67
|
+
if (['class', 'interface', 'enum', 'record', 'annotation'].includes(blockStack[index].kind)) return blockStack[index];
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function javaMethodTarget(owner, modifiers, methodName) {
|
|
73
|
+
if (!owner) return { name: methodName };
|
|
74
|
+
const receiverKind = /\bstatic\b/.test(modifiers) ? 'static' : 'member';
|
|
75
|
+
return { name: receiverKind === 'static' ? `${owner.name}.static.${methodName}` : `${owner.name}.${methodName}`, owner: owner.name, receiverKind };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function javaModifiers(raw) {
|
|
79
|
+
return splitParameters(String(raw ?? '').trim().replace(/\s+/g, ','));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function javaTypeStackKind(kind) {
|
|
83
|
+
if (kind === '@interface') return 'annotation';
|
|
84
|
+
return String(kind).replace(/\s+/g, ' ');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function braceDelta(source) {
|
|
88
|
+
return [...String(source ?? '')].reduce((delta, char) => delta + (char === '{' ? 1 : char === '}' ? -1 : 0), 0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function javaSymbolKind(kind) {
|
|
92
|
+
if (kind === 'interface' || kind === '@interface') return 'interface';
|
|
93
|
+
if (kind === 'enum' || kind === 'record') return 'type';
|
|
94
|
+
return 'class';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { scanJava };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { jsControlKeyword, nativeDeclaration, nativeSignatureDeclaration, splitParameters } from './native-region-scanner-core.js';
|
|
2
|
+
import { jsInitializerKind, jsVariableHasBody } from './native-region-scanner-js-helpers.js';
|
|
3
|
+
|
|
4
|
+
function jsClassMemberDeclaration(input, lineNumber, declarationLine, className) {
|
|
5
|
+
const method = jsClassMethodMatch(declarationLine);
|
|
6
|
+
if (method && !jsControlKeyword(method.name)) return jsClassMethodDeclaration(input, lineNumber, method, className);
|
|
7
|
+
const property = jsClassPropertyMatch(declarationLine);
|
|
8
|
+
if (!property || jsControlKeyword(property.name)) return undefined;
|
|
9
|
+
return jsClassPropertyDeclaration(input, lineNumber, property, className);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function jsInlineClassMemberDeclarations(input, lineNumber, declarationLine, className) {
|
|
13
|
+
const open = declarationLine.indexOf('{');
|
|
14
|
+
const close = declarationLine.lastIndexOf('}');
|
|
15
|
+
if (open < 0 || close <= open) return [];
|
|
16
|
+
const body = declarationLine.slice(open + 1, close);
|
|
17
|
+
const declarations = [];
|
|
18
|
+
const pattern = /((?:(?:public|private|protected|static|async|override|readonly|abstract|accessor|get|set)\s+)*)(?:async\s+)?(?:get\s+|set\s+)?(#?[A-Za-z_$][\w$]*)\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={;]+)?\s*(?:\{|=>)/g;
|
|
19
|
+
for (const match of body.matchAll(pattern)) {
|
|
20
|
+
const method = { modifiers: match[1], name: match[2], parameters: match[3], source: match[0] };
|
|
21
|
+
if (!jsControlKeyword(method.name)) declarations.push(jsClassMethodDeclaration(input, lineNumber, method, className));
|
|
22
|
+
}
|
|
23
|
+
return declarations;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function jsClassMethodMatch(declarationLine) {
|
|
27
|
+
const match = declarationLine.match(/^((?:(?:public|private|protected|static|async|override|readonly|abstract|accessor|get|set)\s+)*)(?:async\s+)?(?:get\s+|set\s+)?(#?[A-Za-z_$][\w$]*)\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={]+)?(?:\{|=>|$)/);
|
|
28
|
+
if (!match) return undefined;
|
|
29
|
+
return { modifiers: match[1], name: match[2], parameters: match[3], source: declarationLine };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function jsClassPropertyMatch(declarationLine) {
|
|
33
|
+
const match = declarationLine.match(/^((?:(?:public|private|protected|static|readonly|declare|accessor)\s+)*)(#?[A-Za-z_$][\w$]*)[?!]?\s*(?::\s*([^=;{]+))?(?:[=;]|$)/);
|
|
34
|
+
if (!match) return undefined;
|
|
35
|
+
return { modifiers: match[1], name: match[2], source: declarationLine, valueType: match[3]?.trim() };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function jsClassMethodDeclaration(input, lineNumber, method, className) {
|
|
39
|
+
const target = jsClassMemberTarget(className, method.modifiers, method.name);
|
|
40
|
+
const hasBody = String(method.source ?? '').includes('{') || String(method.source ?? '').includes('=>');
|
|
41
|
+
return (hasBody ? nativeDeclaration : nativeSignatureDeclaration)(input, lineNumber, 'MethodDefinition', 'method', target.name, {
|
|
42
|
+
methodName: method.name,
|
|
43
|
+
owner: className,
|
|
44
|
+
receiverKind: target.receiverKind,
|
|
45
|
+
accessorKind: jsAccessorKind(method.modifiers),
|
|
46
|
+
modifiers: jsModifiers(method.modifiers),
|
|
47
|
+
parameters: splitParameters(method.parameters)
|
|
48
|
+
}, hasBody, { metadata: jsClassMemberMetadata(className, target, method.name, method.modifiers) });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function jsClassPropertyDeclaration(input, lineNumber, property, className) {
|
|
52
|
+
const initializerKind = jsInitializerKind(property.source ?? '', property.name);
|
|
53
|
+
const hasBody = jsVariableHasBody(initializerKind, property.source ?? '');
|
|
54
|
+
const target = jsClassMemberTarget(className, property.modifiers, property.name);
|
|
55
|
+
return nativeDeclaration(input, lineNumber, 'PropertyDefinition', initializerKind === 'function' ? 'function' : 'property', target.name, {
|
|
56
|
+
propertyName: property.name,
|
|
57
|
+
owner: className,
|
|
58
|
+
receiverKind: target.receiverKind,
|
|
59
|
+
valueType: property.valueType,
|
|
60
|
+
initializerKind,
|
|
61
|
+
modifiers: jsModifiers(property.modifiers)
|
|
62
|
+
}, hasBody, {
|
|
63
|
+
regionKind: initializerKind === 'function' ? 'body' : 'property',
|
|
64
|
+
metadata: {
|
|
65
|
+
initializerKind,
|
|
66
|
+
...jsClassMemberMetadata(className, target, property.name, property.modifiers)
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function jsClassMemberTarget(className, modifiers, memberName) {
|
|
72
|
+
const receiverKind = /\bstatic\b/.test(modifiers) ? 'static' : 'member';
|
|
73
|
+
return {
|
|
74
|
+
name: receiverKind === 'static' ? `${className}.static.${memberName}` : `${className}.${memberName}`,
|
|
75
|
+
receiverKind
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function jsClassMemberMetadata(owner, target, memberName, modifiers) {
|
|
80
|
+
return {
|
|
81
|
+
owner,
|
|
82
|
+
receiverKind: target.receiverKind,
|
|
83
|
+
propertyName: memberName,
|
|
84
|
+
methodName: memberName,
|
|
85
|
+
modifiers: jsModifiers(modifiers),
|
|
86
|
+
accessorKind: jsAccessorKind(modifiers)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function jsAccessorKind(modifiers) {
|
|
91
|
+
if (/\bget\b/.test(modifiers)) return 'get';
|
|
92
|
+
if (/\bset\b/.test(modifiers)) return 'set';
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function jsModifiers(raw) {
|
|
97
|
+
return String(raw ?? '').trim().split(/\s+/).filter(Boolean);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { jsClassMemberDeclaration, jsInlineClassMemberDeclarations };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
jsControlKeyword,
|
|
3
2
|
nativeDeclaration,
|
|
4
3
|
splitParameters
|
|
5
4
|
} from './native-region-scanner-core.js';
|
|
6
|
-
import { jsImportDeclarations } from './native-region-scanner-js-imports.js';
|
|
5
|
+
import { jsExportDeclarations, jsImportDeclarations } from './native-region-scanner-js-imports.js';
|
|
7
6
|
function jsCommentOnlyLine(trimmed) {
|
|
8
7
|
return trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*');
|
|
9
8
|
}
|
|
@@ -71,13 +70,8 @@ function jsObjectRegionContext(name, declarationLine, lineNumber, regionKind) {
|
|
|
71
70
|
if (initializerKind !== 'object' && initializerKind !== 'array') return undefined;
|
|
72
71
|
const depth = jsContainerDelta(declarationLine);
|
|
73
72
|
if (depth <= 0) return undefined;
|
|
74
|
-
return {
|
|
75
|
-
|
|
76
|
-
regionKind: regionKind ?? jsRegionKindForDeclarationName(name, declarationLine),
|
|
77
|
-
initializerKind,
|
|
78
|
-
depth,
|
|
79
|
-
startLine: lineNumber
|
|
80
|
-
};
|
|
73
|
+
return { name, regionKind: regionKind ?? jsRegionKindForDeclarationName(name, declarationLine), initializerKind, depth, startLine: lineNumber,
|
|
74
|
+
arrayRecords: initializerKind === 'array' && /(?:define|create|make|build)\w*(?:tools?|actions?|handlers?|commands?|events?|effects?|workflows?)/i.test(declarationLine) };
|
|
81
75
|
}
|
|
82
76
|
|
|
83
77
|
function jsInitializerKind(line, name) {
|
|
@@ -127,15 +121,17 @@ function jsExportedContainerDeclaration(input, lineNumber, trimmed) {
|
|
|
127
121
|
}
|
|
128
122
|
|
|
129
123
|
function jsExportedFunctionWrapperDeclaration(input, lineNumber, trimmed) {
|
|
130
|
-
const match = trimmed.match(/^export\s+default\s+(
|
|
124
|
+
const match = trimmed.match(/^export\s+default\s+(.+)$/);
|
|
131
125
|
if (!match) return undefined;
|
|
132
|
-
const
|
|
133
|
-
|
|
126
|
+
const unwrapped = jsUnwrapFunctionWrapperArgument(match[1]);
|
|
127
|
+
if (!unwrapped) return undefined;
|
|
128
|
+
const { wrapper, wrappers, argument } = unwrapped;
|
|
129
|
+
const wrapperFields = { wrapper, ...(wrappers.length > 1 ? { wrappers } : {}) };
|
|
134
130
|
let functionMatch = argument.match(/^(?:async\s+)?function\*?\s*([A-Za-z_$][\w$]*)?\s*(?:<[^({;]+>)?\s*\(([^)]*)\)/);
|
|
135
131
|
if (functionMatch) {
|
|
136
132
|
return nativeDeclaration(input, lineNumber, 'ExportDefaultFunctionWrapperDeclaration', 'function', functionMatch[1] ?? 'default', {
|
|
137
133
|
exportDefault: true,
|
|
138
|
-
|
|
134
|
+
...wrapperFields,
|
|
139
135
|
parameters: splitParameters(functionMatch[2])
|
|
140
136
|
}, true);
|
|
141
137
|
}
|
|
@@ -143,7 +139,7 @@ function jsExportedFunctionWrapperDeclaration(input, lineNumber, trimmed) {
|
|
|
143
139
|
if (functionMatch) {
|
|
144
140
|
return nativeDeclaration(input, lineNumber, 'ExportDefaultFunctionWrapperDeclaration', 'function', 'default', {
|
|
145
141
|
exportDefault: true,
|
|
146
|
-
|
|
142
|
+
...wrapperFields,
|
|
147
143
|
parameters: splitParameters(functionMatch[1] ?? functionMatch[2])
|
|
148
144
|
}, true);
|
|
149
145
|
}
|
|
@@ -151,21 +147,33 @@ function jsExportedFunctionWrapperDeclaration(input, lineNumber, trimmed) {
|
|
|
151
147
|
if (classMatch) {
|
|
152
148
|
return nativeDeclaration(input, lineNumber, 'ExportDefaultClassWrapperDeclaration', 'class', classMatch[1] ?? 'default', {
|
|
153
149
|
exportDefault: true,
|
|
154
|
-
|
|
150
|
+
...wrapperFields
|
|
155
151
|
}, true);
|
|
156
152
|
}
|
|
157
153
|
const aliasMatch = argument.match(/^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*(?:[,)]|$)/);
|
|
158
154
|
if (!aliasMatch) return undefined;
|
|
159
155
|
return nativeDeclaration(input, lineNumber, 'ExportDefaultWrappedAlias', 'variable', 'default', {
|
|
160
156
|
exportDefault: true,
|
|
161
|
-
|
|
157
|
+
...wrapperFields,
|
|
162
158
|
alias: aliasMatch[1],
|
|
163
159
|
initializerKind: 'function-wrapper'
|
|
164
160
|
}, false, {
|
|
165
|
-
metadata: { exportDefault: true,
|
|
161
|
+
metadata: { exportDefault: true, ...wrapperFields, alias: aliasMatch[1], initializerKind: 'function-wrapper' }
|
|
166
162
|
});
|
|
167
163
|
}
|
|
168
164
|
|
|
165
|
+
function jsUnwrapFunctionWrapperArgument(source) {
|
|
166
|
+
const wrappers = [];
|
|
167
|
+
let argument = String(source ?? '').trim();
|
|
168
|
+
let match;
|
|
169
|
+
while ((match = argument.match(/^((?:React\.)?(?:forwardRef|memo|lazy|observer)|Object\.freeze)\s*(?:<[^>]+>)?\s*\(\s*(.+)$/))) {
|
|
170
|
+
wrappers.push(match[1]);
|
|
171
|
+
argument = match[2].trim();
|
|
172
|
+
}
|
|
173
|
+
if (!wrappers.length) return undefined;
|
|
174
|
+
return { wrapper: wrappers[0], wrappers, argument };
|
|
175
|
+
}
|
|
176
|
+
|
|
169
177
|
function jsExportAliasDeclaration(input, lineNumber, trimmed) {
|
|
170
178
|
let match = trimmed.match(/^export\s+default\s+([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*;?$/);
|
|
171
179
|
if (match) return jsAliasExport(input, lineNumber, 'ExportDefaultAlias', 'default', match[1], { exportDefault: true }, trimmed);
|
|
@@ -202,72 +210,6 @@ function jsContainerExport(input, lineNumber, languageKind, name, initializer, f
|
|
|
202
210
|
return { declaration, context };
|
|
203
211
|
}
|
|
204
212
|
|
|
205
|
-
function jsObjectPropertyDeclaration(input, lineNumber, trimmed, context) {
|
|
206
|
-
if (/^[}\])]/.test(trimmed) || trimmed.startsWith('...')) return undefined;
|
|
207
|
-
const methodMatch = trimmed.match(/^(?:(?:async|get|set)\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|,|$)/);
|
|
208
|
-
if (methodMatch && !jsControlKeyword(methodMatch[2])) {
|
|
209
|
-
const name = `${context.name}.${methodMatch[2]}`;
|
|
210
|
-
return nativeDeclaration(input, lineNumber, 'ObjectMethod', 'function', name, {
|
|
211
|
-
owner: context.name,
|
|
212
|
-
propertyName: methodMatch[2],
|
|
213
|
-
parameters: splitParameters(methodMatch[3])
|
|
214
|
-
}, true, {
|
|
215
|
-
regionKind: jsPropertyRegionKind(context, methodMatch[2], 'function'),
|
|
216
|
-
metadata: { owner: context.name, propertyName: methodMatch[2], initializerKind: 'function' }
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
const propertyMatch = trimmed.match(/^(?:(['"])([^'"]+)\1|([A-Za-z_$][\w$-]*))\s*:\s*(.+?)(?:,)?$/);
|
|
220
|
-
if (!propertyMatch) return undefined;
|
|
221
|
-
const propertyName = propertyMatch[2] ?? propertyMatch[3];
|
|
222
|
-
if (!propertyName || jsControlKeyword(propertyName)) return undefined;
|
|
223
|
-
const value = propertyMatch[4].trim();
|
|
224
|
-
const initializerKind = jsPropertyInitializerKind(value);
|
|
225
|
-
const functionLike = initializerKind === 'function';
|
|
226
|
-
const name = `${context.name}.${propertyName}`;
|
|
227
|
-
return nativeDeclaration(input, lineNumber, functionLike ? 'ObjectFunctionProperty' : 'ObjectProperty', functionLike ? 'function' : 'property', name, {
|
|
228
|
-
owner: context.name,
|
|
229
|
-
propertyName,
|
|
230
|
-
initializerKind
|
|
231
|
-
}, functionLike || initializerKind === 'object' || initializerKind === 'array', {
|
|
232
|
-
regionKind: jsPropertyRegionKind(context, propertyName, value),
|
|
233
|
-
metadata: { owner: context.name, propertyName, initializerKind }
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function jsRouteRecordDeclaration(input, lineNumber, trimmed, context) {
|
|
238
|
-
if (context.regionKind !== 'route') return undefined;
|
|
239
|
-
const match = trimmed.match(/^(?:\{\s*)?(?:path|route|href|url)\s*:\s*(['"`])([^'"`]+)\1/);
|
|
240
|
-
if (!match) return undefined;
|
|
241
|
-
const routePath = match[2];
|
|
242
|
-
return nativeDeclaration(input, lineNumber, 'RouteRecord', 'route', `${context.name}.${routePath}`, {
|
|
243
|
-
owner: context.name,
|
|
244
|
-
routePath
|
|
245
|
-
}, true, {
|
|
246
|
-
regionKind: 'route',
|
|
247
|
-
metadata: { owner: context.name, routePath, initializerKind: 'object' }
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function jsPropertyInitializerKind(value) {
|
|
252
|
-
const text = String(value ?? '').trim();
|
|
253
|
-
if (/^(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(text)) return 'function';
|
|
254
|
-
const containerKind = jsContainerInitializerKind(text, undefined, text);
|
|
255
|
-
if (containerKind) return containerKind;
|
|
256
|
-
if (/^['"`]/.test(text)) return 'string';
|
|
257
|
-
if (/^(?:true|false)\b/.test(text)) return 'boolean';
|
|
258
|
-
if (/^[0-9]/.test(text)) return 'number';
|
|
259
|
-
return 'expression';
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function jsPropertyRegionKind(context, propertyName, value) {
|
|
263
|
-
const named = jsRegionKindForDeclarationName(propertyName, value);
|
|
264
|
-
if (named) return named;
|
|
265
|
-
if (context.regionKind === 'route') return 'route';
|
|
266
|
-
if (context.regionKind === 'content') return 'content';
|
|
267
|
-
if (context.regionKind === 'config') return 'config';
|
|
268
|
-
return 'property';
|
|
269
|
-
}
|
|
270
|
-
|
|
271
213
|
function jsContainerInitializerKind(initializer, name, source) {
|
|
272
214
|
const text = String(initializer ?? '').trim();
|
|
273
215
|
if (text.startsWith('{')) return 'object';
|
|
@@ -279,7 +221,7 @@ function jsContainerInitializerKind(initializer, name, source) {
|
|
|
279
221
|
|
|
280
222
|
function jsContainerWrapperLooksSemantic(callee, name, source) {
|
|
281
223
|
const signal = `${callee ?? ''} ${name ?? ''} ${source ?? ''}`.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase();
|
|
282
|
-
return /\b(define|create|make|build|object\.freeze)\b/.test(signal) && /\b(config|settings|options|routes?|router|content|docs?|schema|registry|manifest|catalog|menu|nav)\b/.test(signal);
|
|
224
|
+
return /\b(define|create|make|build|object\.freeze)\b/.test(signal) && /\b(actions?|handlers?|tools?|commands?|events?|effects?|workflows?|config|settings|options|routes?|router|content|docs?|schema|registry|manifest|catalog|menu|nav)\b/.test(signal);
|
|
283
225
|
}
|
|
284
226
|
|
|
285
227
|
function jsContainerDelta(source) {
|
|
@@ -316,5 +258,5 @@ function findUnescapedBacktick(text, startIndex) {
|
|
|
316
258
|
|
|
317
259
|
export { jsCommentOnlyLine, jsContainerDelta, jsDeclarationScanLine };
|
|
318
260
|
export { jsExportAliasDeclaration, jsExportedContainerDeclaration, jsExportedFunctionWrapperDeclaration };
|
|
319
|
-
export { jsInitializerKind, jsImportDeclarations,
|
|
320
|
-
export { jsRegionKindForDeclarationName,
|
|
261
|
+
export { jsContainerInitializerKind, jsExportDeclarations, jsInitializerKind, jsImportDeclarations, jsObjectRegionContext };
|
|
262
|
+
export { jsRegionKindForDeclarationName, jsVariableHasBody, jsVariableSymbolKind };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
nativeExportDeclaration,
|
|
2
3
|
nativeImportBindingDeclaration,
|
|
3
4
|
nativeImportDeclaration
|
|
4
5
|
} from './native-region-scanner-core.js';
|
|
6
|
+
import { idFragment } from './native-import-utils.js';
|
|
5
7
|
|
|
6
8
|
export function jsImportDeclarations(input, lineNumber, trimmed) {
|
|
7
9
|
const importEquals = trimmed.match(/^import\s+(type\s+)?([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*(['"])([^'"]+)\3\s*\)/);
|
|
@@ -28,7 +30,10 @@ export function jsImportDeclarations(input, lineNumber, trimmed) {
|
|
|
28
30
|
: exportMatch[4]
|
|
29
31
|
? jsNamedImportBindings(exportMatch[4], { typeOnly, reexport: true })
|
|
30
32
|
: [];
|
|
31
|
-
return
|
|
33
|
+
return [
|
|
34
|
+
...jsImportModuleDeclarations(input, lineNumber, importPath, 'ExportFromDeclaration', bindings, { typeOnly, reexport: true, exportStar: Boolean(exportMatch[2]) }),
|
|
35
|
+
...jsExportModuleDeclarations(input, lineNumber, importPath, bindings, { typeOnly, exportStar: Boolean(exportMatch[2]) })
|
|
36
|
+
];
|
|
32
37
|
}
|
|
33
38
|
const destructuredRequireMatch = trimmed.match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=\s*(?:await\s+)?(require|import)\s*\(\s*(['"])([^'"]+)\3\s*\)/);
|
|
34
39
|
if (destructuredRequireMatch) {
|
|
@@ -54,6 +59,34 @@ export function jsImportDeclarations(input, lineNumber, trimmed) {
|
|
|
54
59
|
return [];
|
|
55
60
|
}
|
|
56
61
|
|
|
62
|
+
export function jsExportDeclarations(input, lineNumber, trimmed) {
|
|
63
|
+
if (/^export\s+(?:type\s+)?(?:\*|\{[^}]+\}\s+from\b)/.test(trimmed)) return [];
|
|
64
|
+
const named = trimmed.match(/^export\s+(type\s+)?\{([^}]+)\}\s*;?$/);
|
|
65
|
+
if (named) return jsLocalExportDeclarations(input, lineNumber, named[2], { typeOnly: Boolean(named[1]) });
|
|
66
|
+
const namespace = trimmed.match(/^export\s+as\s+namespace\s+([A-Za-z_$][\w$]*)\s*;?$/);
|
|
67
|
+
if (namespace) return [nativeExportDeclaration(input, lineNumber, namespace[1], 'ExportNamespaceDeclaration', {
|
|
68
|
+
exportKind: 'namespace'
|
|
69
|
+
})];
|
|
70
|
+
const assignment = trimmed.match(/^export\s*=\s*([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*;?$/);
|
|
71
|
+
if (assignment) return [nativeExportDeclaration(input, lineNumber, 'module.exports', 'ExportAssignment', {
|
|
72
|
+
exportKind: 'assignment',
|
|
73
|
+
localName: assignment[1]
|
|
74
|
+
}, { name: 'module.exports' })];
|
|
75
|
+
if (!trimmed.startsWith('export ')) return [];
|
|
76
|
+
const defaultMatch = trimmed.match(/^export\s+default\s+(.+)$/);
|
|
77
|
+
if (defaultMatch) return [nativeExportDeclaration(input, lineNumber, 'default', 'ExportDefaultDeclaration', {
|
|
78
|
+
exportDefault: true,
|
|
79
|
+
localName: jsExportedDeclarationName(defaultMatch[1])
|
|
80
|
+
}, { name: 'default' })];
|
|
81
|
+
const declarationSource = trimmed.replace(/^export\s+(?:declare\s+)?/, '');
|
|
82
|
+
if (!jsExportedDeclarationLooksComplete(declarationSource)) return [];
|
|
83
|
+
const exportedName = jsExportedDeclarationName(declarationSource);
|
|
84
|
+
if (!exportedName) return [];
|
|
85
|
+
return [nativeExportDeclaration(input, lineNumber, exportedName, 'ExportNamedDeclaration', {
|
|
86
|
+
declarationKind: jsExportedDeclarationKind(declarationSource)
|
|
87
|
+
})];
|
|
88
|
+
}
|
|
89
|
+
|
|
57
90
|
function jsDestructuredImportBindings(raw, importKind) {
|
|
58
91
|
return String(raw ?? '')
|
|
59
92
|
.split(',')
|
|
@@ -100,6 +133,47 @@ function jsImportModuleDeclarations(input, lineNumber, importPath, languageKind,
|
|
|
100
133
|
];
|
|
101
134
|
}
|
|
102
135
|
|
|
136
|
+
function jsExportModuleDeclarations(input, lineNumber, importPath, bindings = [], metadata = {}) {
|
|
137
|
+
const exports = bindings.map((binding) => ({
|
|
138
|
+
localName: binding.importedName,
|
|
139
|
+
exportedName: binding.exportedName ?? binding.localName,
|
|
140
|
+
exportKind: binding.importKind,
|
|
141
|
+
...(binding.typeOnly ? { typeOnly: true } : {})
|
|
142
|
+
}));
|
|
143
|
+
const statementName = metadata.exportStar
|
|
144
|
+
? `* from ${importPath}`
|
|
145
|
+
: exports.length
|
|
146
|
+
? `{${exports.map((binding) => binding.exportedName).join(',')}} from ${importPath}`
|
|
147
|
+
: `from ${importPath}`;
|
|
148
|
+
return [
|
|
149
|
+
nativeExportDeclaration(input, lineNumber, statementName, 'ExportFromDeclaration', {
|
|
150
|
+
importPath: String(importPath),
|
|
151
|
+
exportBindings: exports,
|
|
152
|
+
...(metadata.typeOnly ? { typeOnly: true } : {}),
|
|
153
|
+
...(metadata.exportStar ? { exportStar: true } : {})
|
|
154
|
+
}, { symbolKind: 'module', metadata }),
|
|
155
|
+
...exports.map((binding) => nativeExportDeclaration(input, lineNumber, binding.exportedName, 'ExportBinding', {
|
|
156
|
+
...binding,
|
|
157
|
+
importPath: String(importPath)
|
|
158
|
+
}, { metadata: { ...binding, importPath: String(importPath) } }))
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function jsLocalExportDeclarations(input, lineNumber, raw, options = {}) {
|
|
163
|
+
const bindings = jsNamedExportBindings(raw, options);
|
|
164
|
+
if (!bindings.length) return [];
|
|
165
|
+
return [
|
|
166
|
+
nativeExportDeclaration(input, lineNumber, `{${bindings.map((binding) => binding.exportedName).join(',')}}`, 'ExportNamedDeclaration', {
|
|
167
|
+
exportBindings: bindings,
|
|
168
|
+
...(options.typeOnly ? { typeOnly: true } : {})
|
|
169
|
+
}, {
|
|
170
|
+
symbolId: `symbol:${input.language}:export:statement:${idFragment(bindings.map((binding) => binding.exportedName).join('_'))}`,
|
|
171
|
+
metadata: { bindingCount: bindings.length, ...(options.typeOnly ? { typeOnly: true } : {}) }
|
|
172
|
+
}),
|
|
173
|
+
...bindings.map((binding) => nativeExportDeclaration(input, lineNumber, binding.exportedName, 'ExportBinding', binding, { metadata: binding }))
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
|
|
103
177
|
function jsImportBindingsFromClause(clause, options = {}) {
|
|
104
178
|
const source = String(clause ?? '').trim();
|
|
105
179
|
if (!source) return [];
|
|
@@ -142,3 +216,49 @@ function jsNamedImportBinding(raw, options = {}) {
|
|
|
142
216
|
typeOnly
|
|
143
217
|
};
|
|
144
218
|
}
|
|
219
|
+
|
|
220
|
+
function jsNamedExportBindings(raw, options = {}) {
|
|
221
|
+
return String(raw ?? '').split(',').map((part) => jsNamedExportBinding(part, options)).filter(Boolean);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function jsNamedExportBinding(raw, options = {}) {
|
|
225
|
+
let text = String(raw ?? '').trim();
|
|
226
|
+
if (!text) return undefined;
|
|
227
|
+
let typeOnly = Boolean(options.typeOnly);
|
|
228
|
+
if (text.startsWith('type ')) {
|
|
229
|
+
typeOnly = true;
|
|
230
|
+
text = text.slice(5).trim();
|
|
231
|
+
}
|
|
232
|
+
const match = text.match(/^([A-Za-z_$][\w$]*|\*)\s*(?:as\s+([A-Za-z_$][\w$]*|\*))?$/);
|
|
233
|
+
if (!match) return undefined;
|
|
234
|
+
const localName = match[1];
|
|
235
|
+
return { localName, exportedName: match[2] ?? localName, exportKind: typeOnly ? 'type-named' : 'named', typeOnly };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function jsExportedDeclarationName(source) {
|
|
239
|
+
const text = String(source ?? '').trim();
|
|
240
|
+
return text.match(/^(?:async\s+)?function\*?\s+([A-Za-z_$][\w$]*)/)?.[1]
|
|
241
|
+
?? text.match(/^(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/)?.[1]
|
|
242
|
+
?? text.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)/)?.[1]
|
|
243
|
+
?? text.match(/^type\s+([A-Za-z_$][\w$]*)/)?.[1]
|
|
244
|
+
?? text.match(/^interface\s+([A-Za-z_$][\w$]*)/)?.[1]
|
|
245
|
+
?? text.match(/^(?:const\s+)?enum\s+([A-Za-z_$][\w$]*)/)?.[1]
|
|
246
|
+
?? text.match(/^([A-Za-z_$][\w$]*)\b/)?.[1]
|
|
247
|
+
?? 'default';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function jsExportedDeclarationKind(source) {
|
|
251
|
+
const text = String(source ?? '').trim();
|
|
252
|
+
if (/^(?:async\s+)?function/.test(text)) return 'function';
|
|
253
|
+
if (/^(?:abstract\s+)?class/.test(text)) return 'class';
|
|
254
|
+
if (/^interface\b|^type\b|^(?:const\s+)?enum\b/.test(text)) return 'type';
|
|
255
|
+
if (/^(?:const|let|var)\b/.test(text)) return 'variable';
|
|
256
|
+
return 'value';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function jsExportedDeclarationLooksComplete(source) {
|
|
260
|
+
const text = String(source ?? '').trim();
|
|
261
|
+
if (/^(?:async\s+)?function/.test(text)) return text.includes(')') && /[;{]/.test(text);
|
|
262
|
+
if (/^(?:abstract\s+)?class/.test(text)) return text.includes('{') || text.endsWith(';');
|
|
263
|
+
return true;
|
|
264
|
+
}
|