@shapeshift-labs/frontier-lang-compiler 0.2.102 → 0.2.104
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 +13 -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 +58 -0
- package/dist/declarations/js-ts-safe-merge.d.ts +120 -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/native-project-admission-semantic-evidence.d.ts +34 -0
- package/dist/declarations/native-project-admission.d.ts +6 -10
- package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
- package/dist/declarations/semantic-edit-script.d.ts +10 -4
- package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
- package/dist/declarations/semantic-patch-bundle-overlaps.d.ts +1 -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/createProjectImportAdmissionRecord.js +14 -2
- package/dist/internal/index-impl/diffNativeSymbols.js +82 -1
- package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
- package/dist/internal/index-impl/projectImportAdmissionImportEvidence.js +1 -1
- package/dist/internal/index-impl/projectImportAdmissionSemanticWarnings.js +178 -0
- package/dist/internal/index-impl/projectImportAdmissionSummaries.js +22 -3
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +54 -69
- package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
- package/dist/internal/index-impl/replaySemanticEditProjection.js +78 -78
- 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/semanticEditImportProjection.js +53 -0
- package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
- package/dist/internal/index-impl/semanticEditProjectionRecord.js +108 -0
- package/dist/internal/index-impl/semanticEditReplayAnchors.js +63 -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 +32 -0
- package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
- package/dist/internal/index-impl/semanticPatchBundleAdmission.js +92 -9
- package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +33 -16
- 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 +202 -0
- package/dist/js-ts-safe-merge-analyze.js +279 -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 +64 -0
- package/dist/js-ts-semantic-merge-member-utils.js +18 -0
- package/dist/js-ts-semantic-merge-parse.js +15 -0
- package/dist/js-ts-semantic-merge.js +21 -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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { nativeDeclaration } from './native-region-scanner-core.js';
|
|
2
|
-
import { jsContainerDelta, jsRegionKindForDeclarationName } from './native-region-scanner-js-helpers.js';
|
|
1
|
+
import { jsControlKeyword, nativeDeclaration, splitParameters } from './native-region-scanner-core.js';
|
|
2
|
+
import { jsContainerDelta, jsContainerInitializerKind, jsRegionKindForDeclarationName } from './native-region-scanner-js-helpers.js';
|
|
3
3
|
|
|
4
4
|
function jsCurrentObjectContext(stack) {
|
|
5
5
|
return stack[stack.length - 1];
|
|
@@ -9,6 +9,21 @@ function jsContextAllowsPropertyScan(context) {
|
|
|
9
9
|
return context?.initializerKind === 'object';
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function jsArrayObjectContextFromLine(context, lineNumber, source) {
|
|
13
|
+
if (context?.initializerKind !== 'array' || context.arrayRecords !== true || !String(source ?? '').trim().startsWith('{')) return undefined;
|
|
14
|
+
const depth = jsContainerDelta(source);
|
|
15
|
+
if (depth <= 0) return undefined;
|
|
16
|
+
const index = (context.nextItemIndex ?? 0) + 1;
|
|
17
|
+
context.nextItemIndex = index;
|
|
18
|
+
return { name: `${context.name}.${index}`, ownerName: context.name, regionKind: context.regionKind, initializerKind: 'object', arrayItem: true, depth, startLine: lineNumber };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function updateJsArrayObjectContextName(context, source) {
|
|
22
|
+
if (!context?.arrayItem) return;
|
|
23
|
+
const match = String(source ?? '').trim().match(/^(?:name|id|key|slug|tool|command)\s*:\s*(['"`])([^'"`]+)\1/);
|
|
24
|
+
if (match) context.name = `${context.ownerName}.${match[2]}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
12
27
|
function jsNestedObjectContextFromDeclaration(declaration, lineNumber, source) {
|
|
13
28
|
const initializerKind = declaration?.fields?.initializerKind ?? declaration?.metadata?.initializerKind;
|
|
14
29
|
if (initializerKind !== 'object' && initializerKind !== 'array') return undefined;
|
|
@@ -32,9 +47,9 @@ function jsInlineNestedObjectDeclarations(input, lineNumber, source, parentDecla
|
|
|
32
47
|
for (const entry of splitTopLevelEntries(body)) {
|
|
33
48
|
const parsed = parseObjectEntry(entry);
|
|
34
49
|
if (!parsed) continue;
|
|
35
|
-
const initializerKind = nestedInitializerKind(parsed.value);
|
|
50
|
+
const initializerKind = parsed.method ? 'function' : nestedInitializerKind(parsed.value);
|
|
36
51
|
const name = `${parentDeclaration.name}.${parsed.key}`;
|
|
37
|
-
const regionKind = nestedPropertyRegionKind(parentDeclaration, parsed.key, parsed.value);
|
|
52
|
+
const regionKind = initializerKind === 'function' ? 'body' : nestedPropertyRegionKind(parentDeclaration, parsed.key, parsed.value);
|
|
38
53
|
const declaration = nativeDeclaration(input, lineNumber, initializerKind === 'function' ? 'NestedObjectFunctionProperty' : 'NestedObjectProperty', initializerKind === 'function' ? 'function' : 'property', name, {
|
|
39
54
|
owner: parentDeclaration.name,
|
|
40
55
|
propertyName: parsed.key,
|
|
@@ -57,6 +72,73 @@ function updateJsObjectContextStack(stack, lineNumber, source) {
|
|
|
57
72
|
while (stack.length && stack[stack.length - 1].depth <= 0) stack.pop();
|
|
58
73
|
}
|
|
59
74
|
|
|
75
|
+
function jsObjectPropertyDeclaration(input, lineNumber, trimmed, context) {
|
|
76
|
+
if (/^[}\])]/.test(trimmed) || trimmed.startsWith('...')) return undefined;
|
|
77
|
+
const methodMatch = trimmed.match(/^(?:(?:async|get|set)\s+)?(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`]?)([A-Za-z_$][\w$-]*)\3)\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|,|$)/);
|
|
78
|
+
const methodName = methodMatch?.[2] ?? methodMatch?.[4];
|
|
79
|
+
if (methodMatch && !jsControlKeyword(methodName)) {
|
|
80
|
+
const name = `${context.name}.${methodName}`;
|
|
81
|
+
return nativeDeclaration(input, lineNumber, 'ObjectMethod', 'function', name, {
|
|
82
|
+
owner: context.name,
|
|
83
|
+
propertyName: methodName,
|
|
84
|
+
parameters: splitParameters(methodMatch[5])
|
|
85
|
+
}, true, {
|
|
86
|
+
regionKind: 'body',
|
|
87
|
+
metadata: { owner: context.name, propertyName: methodName, initializerKind: 'function' }
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const propertyMatch = trimmed.match(/^(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`])([^'"`]+)\3|([A-Za-z_$][\w$-]*))\s*:\s*(.+?)(?:,)?$/);
|
|
91
|
+
if (!propertyMatch) return undefined;
|
|
92
|
+
const propertyName = propertyMatch[2] ?? propertyMatch[4] ?? propertyMatch[5];
|
|
93
|
+
if (!propertyName || jsControlKeyword(propertyName)) return undefined;
|
|
94
|
+
const value = propertyMatch[6].trim();
|
|
95
|
+
const initializerKind = jsPropertyInitializerKind(value);
|
|
96
|
+
const functionLike = initializerKind === 'function';
|
|
97
|
+
const name = `${context.name}.${propertyName}`;
|
|
98
|
+
return nativeDeclaration(input, lineNumber, functionLike ? 'ObjectFunctionProperty' : 'ObjectProperty', functionLike ? 'function' : 'property', name, {
|
|
99
|
+
owner: context.name,
|
|
100
|
+
propertyName,
|
|
101
|
+
initializerKind
|
|
102
|
+
}, functionLike || initializerKind === 'object' || initializerKind === 'array', {
|
|
103
|
+
regionKind: functionLike ? 'body' : jsPropertyRegionKind(context, propertyName, value),
|
|
104
|
+
metadata: { owner: context.name, propertyName, initializerKind }
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function jsRouteRecordDeclaration(input, lineNumber, trimmed, context) {
|
|
109
|
+
if (context.regionKind !== 'route') return undefined;
|
|
110
|
+
const match = trimmed.match(/^(?:\{\s*)?(?:path|route|href|url)\s*:\s*(['"`])([^'"`]+)\1/);
|
|
111
|
+
if (!match) return undefined;
|
|
112
|
+
const routePath = match[2];
|
|
113
|
+
return nativeDeclaration(input, lineNumber, 'RouteRecord', 'route', `${context.name}.${routePath}`, {
|
|
114
|
+
owner: context.name,
|
|
115
|
+
routePath
|
|
116
|
+
}, true, {
|
|
117
|
+
regionKind: 'route',
|
|
118
|
+
metadata: { owner: context.name, routePath, initializerKind: 'object' }
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function jsPropertyInitializerKind(value) {
|
|
123
|
+
const text = String(value ?? '').trim();
|
|
124
|
+
if (/^(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(text)) return 'function';
|
|
125
|
+
const containerKind = jsContainerInitializerKind(text, undefined, text);
|
|
126
|
+
if (containerKind) return containerKind;
|
|
127
|
+
if (/^['"`]/.test(text)) return 'string';
|
|
128
|
+
if (/^(?:true|false)\b/.test(text)) return 'boolean';
|
|
129
|
+
if (/^[0-9]/.test(text)) return 'number';
|
|
130
|
+
return 'expression';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function jsPropertyRegionKind(context, propertyName, value) {
|
|
134
|
+
const named = jsRegionKindForDeclarationName(propertyName, value);
|
|
135
|
+
if (named) return named;
|
|
136
|
+
if (context.regionKind === 'route') return 'route';
|
|
137
|
+
if (context.regionKind === 'content') return 'content';
|
|
138
|
+
if (context.regionKind === 'config') return 'config';
|
|
139
|
+
return 'property';
|
|
140
|
+
}
|
|
141
|
+
|
|
60
142
|
function inlineObjectBody(source) {
|
|
61
143
|
const text = String(source ?? '');
|
|
62
144
|
const open = text.indexOf('{');
|
|
@@ -113,10 +195,12 @@ function splitTopLevelEntries(body) {
|
|
|
113
195
|
}
|
|
114
196
|
|
|
115
197
|
function parseObjectEntry(entry) {
|
|
116
|
-
if (!entry || entry.startsWith('...')
|
|
117
|
-
const match = entry.match(/^(
|
|
118
|
-
if (
|
|
119
|
-
|
|
198
|
+
if (!entry || entry.startsWith('...')) return undefined;
|
|
199
|
+
const match = entry.match(/^(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`])([^'"`]+)\3|([A-Za-z_$][\w$-]*))\s*:\s*(.+)$/s);
|
|
200
|
+
if (match) return { key: match[2] ?? match[4] ?? match[5], value: match[6].trim() };
|
|
201
|
+
const methodMatch = entry.match(/^(?:(?:async|get|set)\s+)?(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`]?)([A-Za-z_$][\w$-]*)\3)\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|$)/s);
|
|
202
|
+
if (!methodMatch) return undefined;
|
|
203
|
+
return { key: methodMatch[2] ?? methodMatch[4], value: entry.trim(), method: true };
|
|
120
204
|
}
|
|
121
205
|
|
|
122
206
|
function nestedInitializerKind(value) {
|
|
@@ -139,9 +223,13 @@ function nestedPropertyRegionKind(parentDeclaration, propertyName, value) {
|
|
|
139
223
|
}
|
|
140
224
|
|
|
141
225
|
export {
|
|
226
|
+
jsArrayObjectContextFromLine,
|
|
142
227
|
jsContextAllowsPropertyScan,
|
|
143
228
|
jsCurrentObjectContext,
|
|
144
229
|
jsInlineNestedObjectDeclarations,
|
|
145
230
|
jsNestedObjectContextFromDeclaration,
|
|
231
|
+
jsObjectPropertyDeclaration,
|
|
232
|
+
jsRouteRecordDeclaration,
|
|
233
|
+
updateJsArrayObjectContextName,
|
|
146
234
|
updateJsObjectContextStack
|
|
147
235
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function jsStructureDelta(source) {
|
|
2
|
+
let value = 0;
|
|
3
|
+
let opened = false;
|
|
4
|
+
let quote;
|
|
5
|
+
let escaped = false;
|
|
6
|
+
for (const char of String(source ?? '')) {
|
|
7
|
+
if (quote) {
|
|
8
|
+
if (escaped) escaped = false;
|
|
9
|
+
else if (char === '\\') escaped = true;
|
|
10
|
+
else if (char === quote) quote = undefined;
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (char === '\'' || char === '"' || char === '`') {
|
|
14
|
+
quote = char;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (char === '{' || char === '[' || char === '(') {
|
|
18
|
+
value += 1;
|
|
19
|
+
opened = true;
|
|
20
|
+
} else if (char === '}' || char === ']' || char === ')') {
|
|
21
|
+
value -= 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { value, opened };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { jsStructureDelta };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
jsControlKeyword,
|
|
3
|
+
nativeDeclaration,
|
|
4
|
+
nativeSignatureDeclaration,
|
|
5
|
+
splitParameters
|
|
6
|
+
} from './native-region-scanner-core.js';
|
|
7
|
+
import { jsRegionKindForDeclarationName } from './native-region-scanner-js-helpers.js';
|
|
8
|
+
import { jsStructureDelta } from './native-region-scanner-js-structure.js';
|
|
9
|
+
|
|
10
|
+
function jsTypeRegionContext(name, declarationLine, lineNumber, regionKind, typeKind) {
|
|
11
|
+
const depth = jsStructureDelta(declarationLine).value;
|
|
12
|
+
if (depth <= 0) return undefined;
|
|
13
|
+
return {
|
|
14
|
+
name,
|
|
15
|
+
typeKind,
|
|
16
|
+
regionKind,
|
|
17
|
+
depth,
|
|
18
|
+
startLine: lineNumber,
|
|
19
|
+
memberStack: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function jsCurrentTypeMemberContext(context) {
|
|
24
|
+
return context.memberStack.at(-1) ?? context;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function updateJsTypeRegionContext(context, lineNumber, source) {
|
|
28
|
+
const delta = jsStructureDelta(source).value;
|
|
29
|
+
context.depth += delta;
|
|
30
|
+
for (const memberContext of context.memberStack) {
|
|
31
|
+
if (memberContext.startLine !== lineNumber) memberContext.depth += delta;
|
|
32
|
+
}
|
|
33
|
+
while (context.memberStack.length && context.memberStack.at(-1).depth <= 0) context.memberStack.pop();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function jsTypeMemberDeclaration(input, lineNumber, declarationLine, context) {
|
|
37
|
+
const text = String(declarationLine ?? '').trim();
|
|
38
|
+
if (!text || /^[}\])]/.test(text) || text.startsWith('//')) return undefined;
|
|
39
|
+
let match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*([^;,]+))?[;,]?$/);
|
|
40
|
+
if (match && !jsControlKeyword(match[2])) {
|
|
41
|
+
return nativeSignatureDeclaration(input, lineNumber, 'TypeMethodSignature', 'method', `${context.name}.${match[2]}`, {
|
|
42
|
+
owner: context.name,
|
|
43
|
+
propertyName: match[2],
|
|
44
|
+
parameters: splitParameters(match[3]),
|
|
45
|
+
returnType: match[4]?.trim(),
|
|
46
|
+
typeKind: context.typeKind
|
|
47
|
+
}, false, {
|
|
48
|
+
regionKind: jsTypeMemberRegionKind(context, match[2], text),
|
|
49
|
+
metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*:\s*(.+?)[;,]?$/);
|
|
53
|
+
if (!match || jsControlKeyword(match[2])) return undefined;
|
|
54
|
+
const valueType = match[3].trim();
|
|
55
|
+
const functionLike = /=>/.test(valueType) || /^\([^)]*\)\s*=>/.test(valueType);
|
|
56
|
+
const hasNestedTypeLiteralBody = jsTypeMemberValueStartsTypeLiteral(valueType) && jsStructureDelta(text).value > 0;
|
|
57
|
+
return (functionLike ? nativeSignatureDeclaration : nativeDeclaration)(input, lineNumber, functionLike ? 'TypeFunctionPropertySignature' : 'TypePropertySignature', functionLike ? 'function' : 'property', `${context.name}.${match[2]}`, {
|
|
58
|
+
owner: context.name,
|
|
59
|
+
propertyName: match[2],
|
|
60
|
+
valueType,
|
|
61
|
+
typeKind: context.typeKind
|
|
62
|
+
}, hasNestedTypeLiteralBody, {
|
|
63
|
+
regionKind: jsTypeMemberRegionKind(context, match[2], text),
|
|
64
|
+
metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function jsNestedTypeMemberContextFromDeclaration(declaration, lineNumber, source, parentContext) {
|
|
69
|
+
if (!declaration) return undefined;
|
|
70
|
+
const depth = jsStructureDelta(source).value;
|
|
71
|
+
if (depth <= 0) return undefined;
|
|
72
|
+
const valueType = declaration.fields?.valueType ?? declaration.fields?.returnType;
|
|
73
|
+
const nestedTypeLiteral = jsTypeMemberValueStartsTypeLiteral(valueType);
|
|
74
|
+
return {
|
|
75
|
+
name: nestedTypeLiteral ? declaration.name : parentContext.name,
|
|
76
|
+
typeKind: parentContext.typeKind,
|
|
77
|
+
regionKind: nestedTypeLiteral ? (declaration.regionKind ?? 'property') : parentContext.regionKind,
|
|
78
|
+
depth,
|
|
79
|
+
startLine: lineNumber,
|
|
80
|
+
suppressMembers: !nestedTypeLiteral
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function jsTypeMemberValueStartsTypeLiteral(valueType) {
|
|
85
|
+
const text = String(valueType ?? '').trim();
|
|
86
|
+
return text.startsWith('{') || /=>\s*\{\s*$/.test(text);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function jsTypeMemberRegionKind(context, propertyName) {
|
|
90
|
+
return jsRegionKindForDeclarationName(propertyName) ?? (context.regionKind === 'type' ? 'property' : context.regionKind) ?? 'property';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
jsCurrentTypeMemberContext,
|
|
95
|
+
jsNestedTypeMemberContextFromDeclaration,
|
|
96
|
+
jsTypeMemberDeclaration,
|
|
97
|
+
jsTypeRegionContext,
|
|
98
|
+
updateJsTypeRegionContext
|
|
99
|
+
};
|
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
import {
|
|
2
2
|
braceDelta,
|
|
3
|
-
|
|
4
|
-
nativeDeclaration,
|
|
5
|
-
nativeImportDeclaration,
|
|
3
|
+
nativeDeclaration, nativeImportDeclaration, nativeSignatureDeclaration,
|
|
6
4
|
sourceLines,
|
|
7
5
|
splitParameters
|
|
8
6
|
} from './native-region-scanner-core.js';
|
|
9
7
|
import {
|
|
10
8
|
jsCommentOnlyLine,
|
|
11
|
-
jsContainerDelta,
|
|
12
9
|
jsDeclarationScanLine,
|
|
13
|
-
jsExportAliasDeclaration,
|
|
10
|
+
jsExportAliasDeclaration, jsExportDeclarations,
|
|
14
11
|
jsExportedContainerDeclaration,
|
|
15
12
|
jsExportedFunctionWrapperDeclaration,
|
|
16
13
|
jsInitializerKind,
|
|
17
14
|
jsImportDeclarations,
|
|
18
|
-
jsObjectPropertyDeclaration,
|
|
19
15
|
jsObjectRegionContext,
|
|
20
16
|
jsRegionKindForDeclarationName,
|
|
21
|
-
jsRouteRecordDeclaration,
|
|
22
17
|
jsVariableHasBody,
|
|
23
18
|
jsVariableSymbolKind
|
|
24
19
|
} from './native-region-scanner-js-helpers.js';
|
|
20
|
+
import { jsStructureDelta } from './native-region-scanner-js-structure.js';
|
|
25
21
|
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
jsCurrentTypeMemberContext,
|
|
23
|
+
jsNestedTypeMemberContextFromDeclaration,
|
|
24
|
+
jsTypeMemberDeclaration,
|
|
25
|
+
jsTypeRegionContext,
|
|
26
|
+
updateJsTypeRegionContext
|
|
27
|
+
} from './native-region-scanner-js-types.js';
|
|
28
|
+
import {
|
|
29
|
+
jsArrayObjectContextFromLine, jsContextAllowsPropertyScan, jsCurrentObjectContext,
|
|
30
|
+
jsInlineNestedObjectDeclarations, jsNestedObjectContextFromDeclaration,
|
|
31
|
+
jsObjectPropertyDeclaration, jsRouteRecordDeclaration,
|
|
32
|
+
updateJsArrayObjectContextName, updateJsObjectContextStack
|
|
31
33
|
} from './native-region-scanner-js-nested.js';
|
|
34
|
+
import {
|
|
35
|
+
jsClassMemberDeclaration,
|
|
36
|
+
jsInlineClassMemberDeclarations
|
|
37
|
+
} from './native-region-scanner-js-class.js';
|
|
32
38
|
|
|
33
39
|
function scanJavaScriptLike(input) {
|
|
34
40
|
const declarations = [];
|
|
35
41
|
const lines = sourceLines(input.sourceText);
|
|
36
42
|
const pushDeclaration = (declaration) => {
|
|
37
|
-
if (declaration)
|
|
43
|
+
if (!declaration) return undefined;
|
|
44
|
+
const declarationWithSpan = jsDeclarationWithSourceSpan(input, declaration, lines);
|
|
45
|
+
declarations.push(declarationWithSpan);
|
|
46
|
+
return declarationWithSpan;
|
|
38
47
|
};
|
|
39
48
|
const pushDeclarations = (items) => {
|
|
40
49
|
for (const declaration of items ?? []) pushDeclaration(declaration);
|
|
@@ -51,14 +60,22 @@ function scanJavaScriptLike(input) {
|
|
|
51
60
|
const declarationLine = trimmed.replace(/^(?:export\s+)?(?:declare\s+)?/, '');
|
|
52
61
|
let match;
|
|
53
62
|
if (currentType && number !== currentType.startLine) {
|
|
54
|
-
|
|
63
|
+
const typeContext = jsCurrentTypeMemberContext(currentType);
|
|
64
|
+
if (!typeContext.suppressMembers) {
|
|
65
|
+
const typeMember = pushDeclaration(jsTypeMemberDeclaration(input, number, declarationLine, typeContext));
|
|
66
|
+
const nestedTypeContext = jsNestedTypeMemberContextFromDeclaration(typeMember, number, declarationLine, typeContext);
|
|
67
|
+
if (nestedTypeContext) currentType.memberStack.push(nestedTypeContext);
|
|
68
|
+
}
|
|
55
69
|
}
|
|
56
70
|
const currentObject = jsCurrentObjectContext(objectStack);
|
|
57
71
|
if (currentObject) {
|
|
72
|
+
const arrayItemContext = jsArrayObjectContextFromLine(currentObject, number, trimmed);
|
|
73
|
+
if (arrayItemContext) objectStack.push(arrayItemContext);
|
|
58
74
|
const routeRecord = jsRouteRecordDeclaration(input, number, trimmed, currentObject);
|
|
59
75
|
if (routeRecord) {
|
|
60
76
|
pushDeclaration(routeRecord);
|
|
61
77
|
} else if (jsContextAllowsPropertyScan(currentObject)) {
|
|
78
|
+
updateJsArrayObjectContextName(currentObject, trimmed);
|
|
62
79
|
const property = jsObjectPropertyDeclaration(input, number, trimmed, currentObject);
|
|
63
80
|
if (property) {
|
|
64
81
|
pushDeclaration(property);
|
|
@@ -74,9 +91,15 @@ function scanJavaScriptLike(input) {
|
|
|
74
91
|
} else if ((match = trimmed.match(/^import\s*\(\s*['"]([^'"]+)['"]\s*\)/))) {
|
|
75
92
|
pushDeclaration(nativeImportDeclaration(input, number, match[1], 'DynamicImportExpression', 'module'));
|
|
76
93
|
} else if ((match = declarationLine.match(/^(?:async\s+)?function\*?\s+([A-Za-z_$][\w$]*)\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={]+)?/))) {
|
|
77
|
-
|
|
94
|
+
const hasBody = declarationLine.includes('{');
|
|
95
|
+
pushDeclaration((hasBody ? nativeDeclaration : nativeSignatureDeclaration)(input, number, 'FunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2]) }, hasBody));
|
|
78
96
|
} else if ((match = trimmed.match(/^export\s+default\s+(?:async\s+)?function\*?\s*([A-Za-z_$][\w$]*)?\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*[^={]+)?/))) {
|
|
79
97
|
pushDeclaration(nativeDeclaration(input, number, 'ExportDefaultFunctionDeclaration', 'function', match[1] ?? 'default', { parameters: splitParameters(match[2]), exportDefault: true }, trimmed.includes('{')));
|
|
98
|
+
} else if ((match = trimmed.match(/^export\s+default\s+(?:async\s*)?(?:<[^=]+>\s*)?(?:\(([^)]*)\)|([A-Za-z_$][\w$]*))\s*(?::\s*[^=]+)?=>/))) {
|
|
99
|
+
pushDeclaration(nativeDeclaration(input, number, 'ExportDefaultArrowFunctionDeclaration', 'function', 'default', {
|
|
100
|
+
parameters: splitParameters(match[1] ?? match[2]),
|
|
101
|
+
exportDefault: true
|
|
102
|
+
}, true));
|
|
80
103
|
} else if ((match = declarationLine.match(/^(default\s+)?(?:abstract\s+)?class\b(?:\s+(?!(?:extends|implements)\b)([A-Za-z_$][\w$]*))?/)) && (match[1] || match[2])) {
|
|
81
104
|
const className = match[2] ?? 'default';
|
|
82
105
|
const exportDefault = Boolean(match[1]);
|
|
@@ -121,24 +144,43 @@ function scanJavaScriptLike(input) {
|
|
|
121
144
|
if (match.context) objectStack.push(match.context);
|
|
122
145
|
} else if ((match = jsExportAliasDeclaration(input, number, trimmed))) {
|
|
123
146
|
pushDeclaration(match);
|
|
147
|
+
} else if ((match = trimmed.match(/^module\.exports\s*=\s*(?:async\s+)?function\*?\s*([A-Za-z_$][\w$]*)?\s*(?:<[^({;]+>)?\s*\(([^)]*)\)/))) {
|
|
148
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsDefaultFunctionExport', 'function', match[1] ?? 'module.exports', {
|
|
149
|
+
export: 'commonjs',
|
|
150
|
+
parameters: splitParameters(match[2])
|
|
151
|
+
}, true));
|
|
152
|
+
} else if ((match = trimmed.match(/^module\.exports\s*=\s*(?:async\s*)?(?:<[^=]+>\s*)?(?:\(([^)]*)\)|([A-Za-z_$][\w$]*))\s*(?::\s*[^=]+)?=>/))) {
|
|
153
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsDefaultArrowFunctionExport', 'function', 'module.exports', {
|
|
154
|
+
export: 'commonjs',
|
|
155
|
+
parameters: splitParameters(match[1] ?? match[2])
|
|
156
|
+
}, true));
|
|
157
|
+
} else if ((match = trimmed.match(/^module\.exports\s*=\s*(?:abstract\s+)?class\b(?:\s+(?!(?:extends|implements)\b)([A-Za-z_$][\w$]*))?/))) {
|
|
158
|
+
const className = match[1] ?? 'module.exports';
|
|
159
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsDefaultClassExport', 'class', className, { export: 'commonjs' }, trimmed.includes('{')));
|
|
160
|
+
pushDeclarations(jsInlineClassMemberDeclarations(input, number, trimmed, className));
|
|
161
|
+
if (jsStructureDelta(trimmed).value > 0) {
|
|
162
|
+
currentClass = className;
|
|
163
|
+
classDepth = 0;
|
|
164
|
+
}
|
|
124
165
|
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=\s*(?:async\s+)?function\*?\s*\(([^)]*)\)/))) {
|
|
125
166
|
pushDeclaration(nativeDeclaration(input, number, 'CommonJsFunctionExport', 'function', match[1], { parameters: splitParameters(match[2]) }, true));
|
|
167
|
+
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:<[^=]+>\s*)?(?:\(([^)]*)\)|([A-Za-z_$][\w$]*))\s*(?::\s*[^=]+)?=>/))) {
|
|
168
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsFunctionExport', 'function', match[1], { parameters: splitParameters(match[2] ?? match[3]) }, true));
|
|
169
|
+
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=\s*(?:abstract\s+)?class\b(?:\s+(?!(?:extends|implements)\b)([A-Za-z_$][\w$]*))?/))) {
|
|
170
|
+
const className = match[2] ?? match[1];
|
|
171
|
+
pushDeclaration(nativeDeclaration(input, number, 'CommonJsClassExport', 'class', className, { export: 'commonjs', exportName: match[1] }, trimmed.includes('{')));
|
|
172
|
+
pushDeclarations(jsInlineClassMemberDeclarations(input, number, trimmed, className));
|
|
173
|
+
if (jsStructureDelta(trimmed).value > 0) {
|
|
174
|
+
currentClass = className;
|
|
175
|
+
classDepth = 0;
|
|
176
|
+
}
|
|
126
177
|
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=/))) {
|
|
127
178
|
const regionKind = jsRegionKindForDeclarationName(match[1], trimmed);
|
|
128
179
|
pushDeclaration(nativeDeclaration(input, number, 'CommonJsExport', 'variable', match[1], { export: 'commonjs' }, false, { regionKind }));
|
|
129
|
-
} else if (currentClass
|
|
130
|
-
pushDeclaration(
|
|
131
|
-
methodName: match[1],
|
|
132
|
-
owner: currentClass,
|
|
133
|
-
parameters: splitParameters(match[2])
|
|
134
|
-
}, declarationLine.includes('{') || declarationLine.includes('=>')));
|
|
135
|
-
} else if (currentClass && (match = declarationLine.match(/^(?:(?:public|private|protected|static|readonly|declare|accessor)\s+)*(#?[A-Za-z_$][\w$]*)[?!]?\s*(?::\s*([^=;{]+))?(?:[=;]|$)/))) {
|
|
136
|
-
pushDeclaration(nativeDeclaration(input, number, 'PropertyDefinition', 'property', `${currentClass}.${match[1]}`, {
|
|
137
|
-
propertyName: match[1],
|
|
138
|
-
owner: currentClass,
|
|
139
|
-
valueType: match[2]?.trim()
|
|
140
|
-
}, false, { regionKind: 'property' }));
|
|
180
|
+
} else if (currentClass) {
|
|
181
|
+
pushDeclaration(jsClassMemberDeclaration(input, number, declarationLine, currentClass));
|
|
141
182
|
}
|
|
183
|
+
pushDeclarations(jsExportDeclarations(input, number, trimmed));
|
|
142
184
|
if (currentClass) {
|
|
143
185
|
classDepth += braceDelta(trimmed);
|
|
144
186
|
if (classDepth <= 0) {
|
|
@@ -147,7 +189,7 @@ function scanJavaScriptLike(input) {
|
|
|
147
189
|
}
|
|
148
190
|
}
|
|
149
191
|
if (currentType) {
|
|
150
|
-
if (number !== currentType.startLine) currentType
|
|
192
|
+
if (number !== currentType.startLine) updateJsTypeRegionContext(currentType, number, trimmed);
|
|
151
193
|
if (currentType.depth <= 0) currentType = undefined;
|
|
152
194
|
}
|
|
153
195
|
updateJsObjectContextStack(objectStack, number, trimmed);
|
|
@@ -192,94 +234,4 @@ function jsBalancedDeclarationEndLine(input, lines, startLine) {
|
|
|
192
234
|
return startLine;
|
|
193
235
|
}
|
|
194
236
|
|
|
195
|
-
function jsStructureDelta(source) {
|
|
196
|
-
let value = 0;
|
|
197
|
-
let opened = false;
|
|
198
|
-
let quote;
|
|
199
|
-
let escaped = false;
|
|
200
|
-
for (const char of String(source ?? '')) {
|
|
201
|
-
if (quote) {
|
|
202
|
-
if (escaped) escaped = false;
|
|
203
|
-
else if (char === '\\') escaped = true;
|
|
204
|
-
else if (char === quote) quote = undefined;
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
if (char === '\'' || char === '"' || char === '`') {
|
|
208
|
-
quote = char;
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
if (char === '{' || char === '[' || char === '(') {
|
|
212
|
-
value += 1;
|
|
213
|
-
opened = true;
|
|
214
|
-
} else if (char === '}' || char === ']' || char === ')') {
|
|
215
|
-
value -= 1;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return { value, opened };
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function jsTypeRegionContext(name, declarationLine, lineNumber, regionKind, typeKind) {
|
|
222
|
-
const depth = jsStructureDelta(declarationLine).value;
|
|
223
|
-
if (depth <= 0) return undefined;
|
|
224
|
-
return {
|
|
225
|
-
name,
|
|
226
|
-
typeKind,
|
|
227
|
-
regionKind,
|
|
228
|
-
depth,
|
|
229
|
-
startLine: lineNumber
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function jsTypeMemberDeclaration(input, lineNumber, declarationLine, context) {
|
|
234
|
-
const text = String(declarationLine ?? '').trim();
|
|
235
|
-
if (!text || /^[}\])]/.test(text) || text.startsWith('//')) return undefined;
|
|
236
|
-
let match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*([^;,]+))?[;,]?$/);
|
|
237
|
-
if (match && !jsControlKeyword(match[2])) {
|
|
238
|
-
return nativeDeclaration(input, lineNumber, 'TypeMethodSignature', 'method', `${context.name}.${match[2]}`, {
|
|
239
|
-
owner: context.name,
|
|
240
|
-
propertyName: match[2],
|
|
241
|
-
parameters: splitParameters(match[3]),
|
|
242
|
-
returnType: match[4]?.trim(),
|
|
243
|
-
typeKind: context.typeKind
|
|
244
|
-
}, false, {
|
|
245
|
-
regionKind: jsTypeMemberRegionKind(context, match[2], text),
|
|
246
|
-
metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*:\s*(.+?)[;,]?$/);
|
|
250
|
-
if (!match || jsControlKeyword(match[2])) return undefined;
|
|
251
|
-
const valueType = match[3].trim();
|
|
252
|
-
const functionLike = /=>/.test(valueType) || /^\([^)]*\)\s*=>/.test(valueType);
|
|
253
|
-
return nativeDeclaration(input, lineNumber, functionLike ? 'TypeFunctionPropertySignature' : 'TypePropertySignature', functionLike ? 'function' : 'property', `${context.name}.${match[2]}`, {
|
|
254
|
-
owner: context.name,
|
|
255
|
-
propertyName: match[2],
|
|
256
|
-
valueType,
|
|
257
|
-
typeKind: context.typeKind
|
|
258
|
-
}, false, {
|
|
259
|
-
regionKind: jsTypeMemberRegionKind(context, match[2], text),
|
|
260
|
-
metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function jsTypeMemberRegionKind(context, propertyName, source) {
|
|
265
|
-
return jsRegionKindForDeclarationName(propertyName, source) ?? (context.regionKind === 'type' ? 'property' : context.regionKind) ?? 'property';
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function jsInlineClassMemberDeclarations(input, lineNumber, declarationLine, className) {
|
|
269
|
-
const open = declarationLine.indexOf('{');
|
|
270
|
-
const close = declarationLine.lastIndexOf('}');
|
|
271
|
-
if (open < 0 || close <= open) return [];
|
|
272
|
-
const body = declarationLine.slice(open + 1, close);
|
|
273
|
-
const declarations = [];
|
|
274
|
-
for (const match of body.matchAll(/(?:(?: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)) {
|
|
275
|
-
if (jsControlKeyword(match[1])) continue;
|
|
276
|
-
declarations.push(nativeDeclaration(input, lineNumber, 'MethodDefinition', 'method', `${className}.${match[1]}`, {
|
|
277
|
-
methodName: match[1],
|
|
278
|
-
owner: className,
|
|
279
|
-
parameters: splitParameters(match[2])
|
|
280
|
-
}, true));
|
|
281
|
-
}
|
|
282
|
-
return declarations;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
237
|
export { scanJavaScriptLike };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { upperFirst } from './native-import-utils.js';
|
|
2
|
+
import { nativeDeclaration, nativeImportDeclaration, sourceLines, splitParameters } from './native-region-scanner-core.js';
|
|
3
|
+
import { braceBlockSpan } from './native-region-scanner-spans.js';
|
|
4
|
+
|
|
5
|
+
function scanKotlin(input) {
|
|
6
|
+
const declarations = [];
|
|
7
|
+
const lines = sourceLines(input.sourceText);
|
|
8
|
+
const blockStack = [];
|
|
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
|
+
let match;
|
|
15
|
+
if ((match = trimmed.match(/^package\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)/))) {
|
|
16
|
+
declarations.push(nativeDeclaration(input, number, 'PackageHeader', 'package', match[1], {}, false));
|
|
17
|
+
} else if ((match = trimmed.match(/^import\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*(?:\.\*)?)(?:\s+as\s+[A-Za-z_]\w*)?$/))) {
|
|
18
|
+
declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDirective', 'package'));
|
|
19
|
+
} else if ((match = trimmed.match(/^(?:(?:public|private|protected|internal|expect|actual|open|final|abstract|sealed|data|value)\s+)*(?:(enum|annotation)\s+)?(class|interface|object)\s+([A-Za-z_]\w*)/))) {
|
|
20
|
+
const owner = nearestContainer(blockStack);
|
|
21
|
+
const name = owner ? `${owner.name}.${match[3]}` : match[3];
|
|
22
|
+
const hasBody = trimmed.includes('{');
|
|
23
|
+
declarations.push(nativeDeclaration(input, number, kotlinDeclarationKind(match[2], match[1]), kotlinSymbolKind(match[2], match[1]), name, owner ? { owner: owner.name } : {}, hasBody, spanOptions(input, lines, index, hasBody)));
|
|
24
|
+
if (hasBody) blockStack.push({ kind: match[2], name, bodyDepth: braceDepth + 1 });
|
|
25
|
+
} else if ((match = trimmed.match(/^(?:(?:public|private|protected|internal|expect|actual|open|final|abstract|inline|tailrec|operator|infix|external|suspend|override)\s+)*fun\s+(?:<[^>]+>\s*)?(?:([A-Za-z_][\w.<>?]*)\.)?([A-Za-z_]\w*)\s*\(([^)]*)\)/))) {
|
|
26
|
+
const owner = nearestContainer(blockStack);
|
|
27
|
+
const receiverType = match[1];
|
|
28
|
+
const target = kotlinFunctionTarget(owner, receiverType, match[2]);
|
|
29
|
+
const hasBody = trimmed.includes('{') || trimmed.includes('=');
|
|
30
|
+
declarations.push(nativeDeclaration(input, number, 'FunctionDeclaration', target.owner ? 'method' : 'function', target.name, {
|
|
31
|
+
parameters: splitParameters(match[3]),
|
|
32
|
+
methodName: match[2],
|
|
33
|
+
...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {}),
|
|
34
|
+
...(receiverType ? { receiverType } : {})
|
|
35
|
+
}, hasBody, {
|
|
36
|
+
...spanOptions(input, lines, index, trimmed.includes('{')),
|
|
37
|
+
metadata: {
|
|
38
|
+
methodName: match[2],
|
|
39
|
+
...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {}),
|
|
40
|
+
...(receiverType ? { receiverType } : {})
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
if (trimmed.includes('{')) blockStack.push({ kind: 'function', name: target.name, bodyDepth: braceDepth + 1 });
|
|
44
|
+
} else if ((match = trimmed.match(/^(?:(?:public|private|protected|internal|expect|actual)\s+)*typealias\s+([A-Za-z_]\w*)\s*=/))) {
|
|
45
|
+
declarations.push(nativeDeclaration(input, number, 'TypeAliasDeclaration', 'type', match[1], {}, false));
|
|
46
|
+
} else if ((match = trimmed.match(/^(?:(?:public|private|protected|internal|expect|actual|open|final|abstract|override|const|lateinit)\s+)*(?:val|var)\s+([A-Za-z_]\w*)\b/))) {
|
|
47
|
+
declarations.push(nativeDeclaration(input, number, 'PropertyDeclaration', 'variable', match[1], {}, false));
|
|
48
|
+
}
|
|
49
|
+
braceDepth = Math.max(0, braceDepth + braceDelta(line));
|
|
50
|
+
}
|
|
51
|
+
return declarations;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function spanOptions(input, lines, index, hasBraceBody) {
|
|
55
|
+
return hasBraceBody ? { span: braceBlockSpan(input, lines, index) } : {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function depthAfterLeadingClosers(trimmed, depth) {
|
|
59
|
+
const closers = String(trimmed).match(/^}+/)?.[0].length ?? 0;
|
|
60
|
+
return Math.max(0, depth - closers);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function nearestContainer(blockStack) {
|
|
64
|
+
for (let index = blockStack.length - 1; index >= 0; index -= 1) {
|
|
65
|
+
if (blockStack[index].kind === 'function') return undefined;
|
|
66
|
+
if (blockStack[index].kind === 'class' || blockStack[index].kind === 'interface' || blockStack[index].kind === 'object') return blockStack[index];
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function kotlinFunctionTarget(owner, receiverType, methodName) {
|
|
72
|
+
if (receiverType) return { name: `${receiverType}.extension.${methodName}`, owner: receiverType, receiverKind: 'extension' };
|
|
73
|
+
if (owner) return { name: `${owner.name}.${methodName}`, owner: owner.name, receiverKind: 'member' };
|
|
74
|
+
return { name: methodName };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function braceDelta(source) {
|
|
78
|
+
return [...String(source ?? '')].reduce((delta, char) => delta + (char === '{' ? 1 : char === '}' ? -1 : 0), 0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function kotlinDeclarationKind(kind, prefix) {
|
|
82
|
+
if (prefix === 'enum') return 'EnumClassDeclaration';
|
|
83
|
+
if (prefix === 'annotation') return 'AnnotationClassDeclaration';
|
|
84
|
+
return `${upperFirst(kind)}Declaration`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function kotlinSymbolKind(kind, prefix) {
|
|
88
|
+
if (kind === 'interface') return 'interface';
|
|
89
|
+
if (kind === 'object') return 'module';
|
|
90
|
+
if (prefix === 'enum' || prefix === 'annotation') return 'type';
|
|
91
|
+
return 'class';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { scanKotlin };
|