@shapeshift-labs/frontier-lang-compiler 0.2.103 → 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.
Files changed (124) hide show
  1. package/README.md +13 -0
  2. package/dist/declarations/bidirectional-target-change-source-edit.d.ts +30 -0
  3. package/dist/declarations/bidirectional-target-change.d.ts +10 -0
  4. package/dist/declarations/js-ts-safe-member-merge.d.ts +58 -0
  5. package/dist/declarations/js-ts-safe-merge.d.ts +120 -0
  6. package/dist/declarations/js-ts-semantic-conflict-sidecars.d.ts +235 -0
  7. package/dist/declarations/js-ts-semantic-merge-contracts.d.ts +287 -0
  8. package/dist/declarations/js-ts-semantic-merge.d.ts +4 -0
  9. package/dist/declarations/native-import-losses.d.ts +3 -0
  10. package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
  11. package/dist/declarations/semantic-edit-script.d.ts +7 -4
  12. package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
  13. package/dist/declarations/semantic-patch-bundle.d.ts +6 -4
  14. package/dist/declarations/semantic-sidecar-example.d.ts +18 -0
  15. package/dist/declarations/semantic-transform-identity.d.ts +3 -0
  16. package/dist/declarations/source-preservation.d.ts +72 -0
  17. package/dist/declarations/universal-capability.d.ts +4 -0
  18. package/dist/declarations/universal-conversion-artifacts.d.ts +61 -1
  19. package/dist/declarations/universal-conversion-compact-counts.d.ts +51 -0
  20. package/dist/declarations/universal-conversion-plan.d.ts +6 -1
  21. package/dist/declarations/universal-representation-coverage.d.ts +90 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +3 -0
  24. package/dist/internal/index-impl/bidirectionalExactSourceBackprojection.js +199 -0
  25. package/dist/internal/index-impl/bidirectionalSameLanguageSourceProjection.js +112 -0
  26. package/dist/internal/index-impl/bidirectionalSourceEditProjection.js +319 -0
  27. package/dist/internal/index-impl/bidirectionalSourceEditProjectionArtifacts.js +67 -0
  28. package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +17 -5
  29. package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +58 -20
  30. package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +60 -7
  31. package/dist/internal/index-impl/createLightweightNativeImport.js +1 -0
  32. package/dist/internal/index-impl/createNativeSourcePreservation.js +28 -2
  33. package/dist/internal/index-impl/diffNativeSymbols.js +3 -3
  34. package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
  35. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +43 -8
  36. package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
  37. package/dist/internal/index-impl/replaySemanticEditProjection.js +39 -19
  38. package/dist/internal/index-impl/semanticEditBundleAdmission.js +7 -3
  39. package/dist/internal/index-impl/semanticEditBundleIndex.js +47 -1
  40. package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +40 -0
  41. package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
  42. package/dist/internal/index-impl/semanticEditProjectionRecord.js +29 -0
  43. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +39 -0
  44. package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +85 -0
  45. package/dist/internal/index-impl/semanticEditScripts.js +4 -0
  46. package/dist/internal/index-impl/semanticEditSourceRanges.js +27 -0
  47. package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
  48. package/dist/internal/index-impl/semanticPatchBundleAdmission.js +41 -7
  49. package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -0
  50. package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +2 -0
  51. package/dist/internal/index-impl/semanticSidecarQuality.js +111 -0
  52. package/dist/internal/index-impl/semanticSourceEditDedupe.js +69 -9
  53. package/dist/internal/index-impl/semanticTransformIdentityRecords.js +85 -9
  54. package/dist/js-ts-safe-member-merge-result.js +158 -0
  55. package/dist/js-ts-safe-member-merge.js +202 -0
  56. package/dist/js-ts-safe-merge-analyze.js +279 -0
  57. package/dist/js-ts-safe-merge-constants.js +50 -0
  58. package/dist/js-ts-safe-merge-context.js +118 -0
  59. package/dist/js-ts-safe-merge-ledger-validation.js +92 -0
  60. package/dist/js-ts-safe-merge-ledger.js +85 -0
  61. package/dist/js-ts-safe-merge-parse-declarations.js +210 -0
  62. package/dist/js-ts-safe-merge-parse-statements.js +155 -0
  63. package/dist/js-ts-safe-merge-plan.js +190 -0
  64. package/dist/js-ts-safe-merge.js +175 -0
  65. package/dist/js-ts-semantic-conflict-sidecar-constants.js +77 -0
  66. package/dist/js-ts-semantic-conflict-sidecar-detectors.js +195 -0
  67. package/dist/js-ts-semantic-conflict-sidecar-normalize.js +203 -0
  68. package/dist/js-ts-semantic-conflict-sidecar-utils.js +190 -0
  69. package/dist/js-ts-semantic-conflict-sidecars.js +81 -0
  70. package/dist/js-ts-semantic-merge-contract-helpers.js +128 -0
  71. package/dist/js-ts-semantic-merge-contracts.js +217 -0
  72. package/dist/js-ts-semantic-merge-member-containers.js +100 -0
  73. package/dist/js-ts-semantic-merge-member-keys.js +142 -0
  74. package/dist/js-ts-semantic-merge-member-segments.js +185 -0
  75. package/dist/js-ts-semantic-merge-member-source.js +64 -0
  76. package/dist/js-ts-semantic-merge-member-utils.js +18 -0
  77. package/dist/js-ts-semantic-merge-parse.js +15 -0
  78. package/dist/js-ts-semantic-merge.js +21 -0
  79. package/dist/lightweight-dependency-effects.js +51 -0
  80. package/dist/lightweight-dependency-language.js +12 -1
  81. package/dist/lightweight-dependency-relations.js +14 -27
  82. package/dist/native-region-scanner-core.js +33 -1
  83. package/dist/native-region-scanner-csharp.js +151 -0
  84. package/dist/native-region-scanner-dart.js +91 -0
  85. package/dist/native-region-scanner-dynamic.js +21 -151
  86. package/dist/native-region-scanner-functional.js +40 -13
  87. package/dist/native-region-scanner-java.js +97 -0
  88. package/dist/native-region-scanner-js-class.js +100 -0
  89. package/dist/native-region-scanner-js-helpers.js +28 -86
  90. package/dist/native-region-scanner-js-imports.js +121 -1
  91. package/dist/native-region-scanner-js-nested.js +96 -8
  92. package/dist/native-region-scanner-js-structure.js +27 -0
  93. package/dist/native-region-scanner-js-types.js +99 -0
  94. package/dist/native-region-scanner-js.js +70 -118
  95. package/dist/native-region-scanner-kotlin.js +94 -0
  96. package/dist/native-region-scanner-main.js +15 -181
  97. package/dist/native-region-scanner-php.js +80 -0
  98. package/dist/native-region-scanner-python.js +62 -0
  99. package/dist/native-region-scanner-ruby.js +72 -0
  100. package/dist/native-region-scanner-scala.js +91 -0
  101. package/dist/native-region-scanner-spans.js +74 -0
  102. package/dist/native-region-scanner-swift.js +155 -0
  103. package/dist/native-region-scanner.js +14 -10
  104. package/dist/native-source-ledger-helpers.js +195 -0
  105. package/dist/native-source-ledger.js +306 -0
  106. package/dist/native-source-preservation-scanner.js +4 -0
  107. package/dist/semantic-import-callsite-regions.js +136 -0
  108. package/dist/semantic-import-effect-regions.js +283 -0
  109. package/dist/semantic-import-regions.js +11 -2
  110. package/dist/semantic-import-sidecar-entry.js +16 -2
  111. package/dist/semantic-import-sidecar-types.d.ts +2 -0
  112. package/dist/semantic-sidecar-example.js +68 -0
  113. package/dist/universal-capability-matrix.js +23 -0
  114. package/dist/universal-conversion-artifact-query.js +79 -2
  115. package/dist/universal-conversion-artifact-semantic-edit.js +103 -0
  116. package/dist/universal-conversion-artifact-summary.js +33 -1
  117. package/dist/universal-conversion-artifacts.js +13 -48
  118. package/dist/universal-conversion-plan-scoring.js +21 -1
  119. package/dist/universal-conversion-plan-summary.js +30 -0
  120. package/dist/universal-conversion-plan.js +25 -9
  121. package/dist/universal-conversion-route-metadata.js +96 -0
  122. package/dist/universal-conversion-route-operations.js +7 -0
  123. package/dist/universal-representation-coverage.js +193 -0
  124. package/package.json +1 -1
@@ -0,0 +1,80 @@
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 scanPhp(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().replace(/^<\?php\s*/, '');
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(/^namespace\s+([A-Za-z_][\w\\]*)\s*;/))) {
17
+ declarations.push(nativeDeclaration(input, number, 'NamespaceDefinition', 'namespace', match[1], {}, false));
18
+ } else if ((match = trimmed.match(/^use\s+([A-Za-z_][\w\\]*)(?:\s+as\s+([A-Za-z_]\w*))?\s*;/))) {
19
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'UseDeclaration', 'namespace'));
20
+ } else if ((match = trimmed.match(/^(?:(?:abstract|final|readonly)\s+)*(class|interface|trait|enum)\s+([A-Za-z_]\w*)/))) {
21
+ const hasBody = trimmed.includes('{');
22
+ declarations.push(nativeDeclaration(input, number, `${upperFirst(match[1])}Declaration`, phpSymbolKind(match[1]), match[2], {}, hasBody, spanOptions(input, lines, index, hasBody)));
23
+ if (hasBody) blockStack.push({ kind: match[1], name: match[2], bodyDepth: braceDepth + 1 });
24
+ } else if ((match = trimmed.match(/^((?:(?:public|protected|private|static|final|abstract)\s+)*)function\s+&?\s*([A-Za-z_]\w*)\s*\(([^)]*)\)/))) {
25
+ const owner = nearestContainer(blockStack);
26
+ const target = phpFunctionTarget(owner, match[1], match[2]);
27
+ const hasBody = trimmed.includes('{');
28
+ declarations.push(nativeDeclaration(input, number, 'FunctionDeclaration', target.owner ? 'method' : 'function', target.name, {
29
+ parameters: splitParameters(match[3]),
30
+ ...(target.owner ? { owner: target.owner, methodName: match[2], receiverKind: target.receiverKind } : {}),
31
+ ...(match[1].trim() ? { modifiers: splitParameters(match[1].trim().replace(/\s+/g, ',')) } : {})
32
+ }, hasBody, {
33
+ ...spanOptions(input, lines, index, hasBody),
34
+ metadata: {
35
+ ...(target.owner ? { owner: target.owner, methodName: match[2], receiverKind: target.receiverKind } : {}),
36
+ ...(match[1].trim() ? { modifiers: splitParameters(match[1].trim().replace(/\s+/g, ',')) } : {})
37
+ }
38
+ }));
39
+ if (hasBody) blockStack.push({ kind: 'function', name: target.name, bodyDepth: braceDepth + 1 });
40
+ }
41
+ braceDepth = Math.max(0, braceDepth + braceDelta(line));
42
+ }
43
+ return declarations;
44
+ }
45
+
46
+ function spanOptions(input, lines, index, hasBraceBody) {
47
+ return hasBraceBody ? { span: braceBlockSpan(input, lines, index) } : {};
48
+ }
49
+
50
+ function depthAfterLeadingClosers(trimmed, depth) {
51
+ const closers = String(trimmed).match(/^}+/)?.[0].length ?? 0;
52
+ return Math.max(0, depth - closers);
53
+ }
54
+
55
+ function nearestContainer(blockStack) {
56
+ for (let index = blockStack.length - 1; index >= 0; index -= 1) {
57
+ if (blockStack[index].kind === 'function') return undefined;
58
+ if (['class', 'interface', 'trait', 'enum'].includes(blockStack[index].kind)) return blockStack[index];
59
+ }
60
+ return undefined;
61
+ }
62
+
63
+ function phpFunctionTarget(owner, modifiers, methodName) {
64
+ if (!owner) return { name: methodName };
65
+ const receiverKind = /\bstatic\b/.test(modifiers) ? 'static' : 'instance';
66
+ return { name: receiverKind === 'static' ? `${owner.name}.static.${methodName}` : `${owner.name}.${methodName}`, owner: owner.name, receiverKind };
67
+ }
68
+
69
+ function braceDelta(source) {
70
+ return [...String(source ?? '')].reduce((delta, char) => delta + (char === '{' ? 1 : char === '}' ? -1 : 0), 0);
71
+ }
72
+
73
+ function phpSymbolKind(kind) {
74
+ if (kind === 'interface') return 'interface';
75
+ if (kind === 'trait') return 'trait';
76
+ if (kind === 'enum') return 'type';
77
+ return 'class';
78
+ }
79
+
80
+ export { scanPhp };
@@ -0,0 +1,62 @@
1
+ import { nativeDeclaration, nativeImportDeclaration, sourceLines, splitParameters } from './native-region-scanner-core.js';
2
+ import { pythonBlockSpan } from './native-region-scanner-spans.js';
3
+
4
+ function scanPython(input) {
5
+ const declarations = [];
6
+ const lines = sourceLines(input.sourceText);
7
+ const blockStack = [];
8
+ let decorators = [];
9
+ for (const [index, { line, number }] of lines.entries()) {
10
+ const trimmed = line.trim();
11
+ if (!trimmed) {
12
+ decorators = [];
13
+ continue;
14
+ }
15
+ const indent = indentationLength(line);
16
+ while (blockStack.length && indent <= blockStack[blockStack.length - 1].indent) blockStack.pop();
17
+
18
+ let match;
19
+ if ((match = trimmed.match(/^@([A-Za-z_][\w.]*(?:\([^)]*\))?)/))) {
20
+ decorators.push(match[1]);
21
+ continue;
22
+ }
23
+ if ((match = trimmed.match(/^(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(([^)]*)\)\s*:/))) {
24
+ const owner = blockStack[blockStack.length - 1]?.kind === 'class' ? blockStack[blockStack.length - 1].name : undefined;
25
+ const name = owner ? `${owner}.${match[1]}` : match[1];
26
+ declarations.push(nativeDeclaration(input, number, 'FunctionDef', owner ? 'method' : 'function', name, {
27
+ parameters: splitParameters(match[2]),
28
+ ...(owner ? { owner, methodName: match[1] } : {}),
29
+ ...(decorators.length ? { decorators } : {})
30
+ }, true, {
31
+ span: pythonBlockSpan(input, lines, index),
32
+ metadata: {
33
+ ...(owner ? { owner, methodName: match[1] } : {}),
34
+ ...(decorators.length ? { decorators } : {})
35
+ }
36
+ }));
37
+ blockStack.push({ kind: 'def', name, indent });
38
+ } else if ((match = trimmed.match(/^class\s+([A-Za-z_]\w*)/))) {
39
+ const owner = blockStack[blockStack.length - 1]?.kind === 'class' ? blockStack[blockStack.length - 1].name : undefined;
40
+ const name = owner ? `${owner}.${match[1]}` : match[1];
41
+ declarations.push(nativeDeclaration(input, number, 'ClassDef', 'class', name, {
42
+ ...(owner ? { owner } : {}),
43
+ ...(decorators.length ? { decorators } : {})
44
+ }, true, {
45
+ span: pythonBlockSpan(input, lines, index),
46
+ metadata: {
47
+ ...(owner ? { owner } : {}),
48
+ ...(decorators.length ? { decorators } : {})
49
+ }
50
+ }));
51
+ blockStack.push({ kind: 'class', name, indent });
52
+ } else if ((match = trimmed.match(/^(?:from\s+([A-Za-z_][\w.]*)\s+import\s+.+|import\s+([A-Za-z_][\w.]*))/))) {
53
+ declarations.push(nativeImportDeclaration(input, number, match[1] ?? match[2], 'Import', 'module'));
54
+ }
55
+ decorators = [];
56
+ }
57
+ return declarations;
58
+ }
59
+
60
+ function indentationLength(line) { return String(line ?? '').match(/^\s*/)?.[0].length ?? 0; }
61
+
62
+ export { scanPython };
@@ -0,0 +1,72 @@
1
+ import { nativeDeclaration, nativeImportDeclaration, sourceLines, splitParameters } from './native-region-scanner-core.js';
2
+ import { endKeywordBlockSpan } from './native-region-scanner-spans.js';
3
+
4
+ function scanRuby(input) {
5
+ const declarations = [];
6
+ const lines = sourceLines(input.sourceText);
7
+ const blockStack = [];
8
+ for (const [index, { line, number }] of lines.entries()) {
9
+ const trimmed = line.trim();
10
+ if (!trimmed) continue;
11
+ if (/^end\b/.test(trimmed)) {
12
+ blockStack.pop();
13
+ continue;
14
+ }
15
+
16
+ let match;
17
+ if ((match = trimmed.match(/^(?:require|load)\s+['"]([^'"]+)['"]/))) {
18
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'Require', 'module'));
19
+ } else if ((match = trimmed.match(/^module\s+([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)/))) {
20
+ const name = qualifiedContainerName(blockStack, match[1]);
21
+ declarations.push(nativeDeclaration(input, number, 'Module', 'module', name, {}, true, endSpanOptions(input, lines, index)));
22
+ blockStack.push({ kind: 'module', name });
23
+ } else if ((match = trimmed.match(/^class\s+([A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)/))) {
24
+ const name = qualifiedContainerName(blockStack, match[1]);
25
+ declarations.push(nativeDeclaration(input, number, 'Class', 'class', name, {}, true, endSpanOptions(input, lines, index)));
26
+ blockStack.push({ kind: 'class', name });
27
+ } else if ((match = trimmed.match(/^def\s+(?:(self|[A-Za-z_]\w*(?:::[A-Za-z_]\w*)*)\.)?([A-Za-z_]\w*[!?=]?)\s*(?:\(([^)]*)\)|([^#=]*))?/))) {
28
+ const owner = nearestContainer(blockStack);
29
+ const target = rubyMethodTarget(owner, match[1], match[2]);
30
+ declarations.push(nativeDeclaration(input, number, 'Def', target.owner ? 'method' : 'function', target.name, {
31
+ parameters: splitParameters(match[3] ?? match[4]),
32
+ methodName: match[2],
33
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {})
34
+ }, true, {
35
+ ...endSpanOptions(input, lines, index),
36
+ metadata: {
37
+ methodName: match[2],
38
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {})
39
+ }
40
+ }));
41
+ blockStack.push({ kind: 'def', name: target.name });
42
+ }
43
+ }
44
+ return declarations;
45
+ }
46
+
47
+ function endSpanOptions(input, lines, index) {
48
+ return { span: endKeywordBlockSpan(input, lines, index) };
49
+ }
50
+
51
+ function qualifiedContainerName(blockStack, name) {
52
+ if (name.includes('::')) return name;
53
+ const owner = nearestContainer(blockStack);
54
+ return owner?.kind === 'module' ? `${owner.name}::${name}` : name;
55
+ }
56
+
57
+ function nearestContainer(blockStack) {
58
+ for (let index = blockStack.length - 1; index >= 0; index -= 1) {
59
+ if (blockStack[index].kind === 'class' || blockStack[index].kind === 'module') return blockStack[index];
60
+ if (blockStack[index].kind === 'def') return undefined;
61
+ }
62
+ return undefined;
63
+ }
64
+
65
+ function rubyMethodTarget(owner, receiver, methodName) {
66
+ if (receiver && receiver !== 'self') return { name: `${receiver}.singleton.${methodName}`, owner: receiver, receiverKind: 'singleton' };
67
+ if (receiver === 'self' && owner) return { name: `${owner.name}.singleton.${methodName}`, owner: owner.name, receiverKind: 'singleton' };
68
+ if (owner) return { name: `${owner.name}.instance.${methodName}`, owner: owner.name, receiverKind: 'instance' };
69
+ return { name: methodName };
70
+ }
71
+
72
+ export { scanRuby };
@@ -0,0 +1,91 @@
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 scanScala(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
+
15
+ let match;
16
+ if ((match = trimmed.match(/^package\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)/))) {
17
+ declarations.push(nativeDeclaration(input, number, 'PackageClause', 'package', match[1], {}, false));
18
+ } else if ((match = trimmed.match(/^import\s+(.+?);?$/))) {
19
+ declarations.push(nativeImportDeclaration(input, number, match[1].trim(), 'Import', 'package'));
20
+ } else if ((match = trimmed.match(/^(?:(?:private|protected|final|sealed|abstract|case|implicit|lazy|override|inline|transparent|open)\s+)*(class|trait|object|enum)\s+([A-Za-z_]\w*)/))) {
21
+ const owner = nearestContainer(blockStack);
22
+ const name = scalaContainerName(owner, match[1], match[2]);
23
+ const hasBody = trimmed.includes('{') || trimmed.includes(':');
24
+ declarations.push(nativeDeclaration(input, number, `${upperFirst(match[1])}Def`, scalaSymbolKind(match[1]), name, owner ? { owner: owner.name } : {}, hasBody, spanOptions(input, lines, index, trimmed.includes('{'))));
25
+ if (trimmed.includes('{')) blockStack.push({ kind: match[1], name, bodyDepth: braceDepth + 1 });
26
+ } else if ((match = trimmed.match(/^(?:(?:private|protected|final|implicit|override|inline)\s+)*def\s+([A-Za-z_]\w*)\s*(?:\[[^\]]+\])?\s*\(([^)]*)\)/))) {
27
+ const owner = nearestContainer(blockStack);
28
+ const target = scalaMethodTarget(owner, match[1]);
29
+ const hasBody = trimmed.includes('{') || trimmed.includes('=');
30
+ declarations.push(nativeDeclaration(input, number, 'DefDef', target.owner ? 'method' : 'function', target.name, {
31
+ parameters: splitParameters(match[2]),
32
+ methodName: match[1],
33
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {})
34
+ }, hasBody, {
35
+ ...spanOptions(input, lines, index, trimmed.includes('{')),
36
+ metadata: {
37
+ methodName: match[1],
38
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind } : {})
39
+ }
40
+ }));
41
+ if (trimmed.includes('{')) blockStack.push({ kind: 'function', name: target.name, bodyDepth: braceDepth + 1 });
42
+ } else if ((match = trimmed.match(/^(?:(?:private|protected|final|implicit|opaque)\s+)*type\s+([A-Za-z_]\w*)\b/))) {
43
+ declarations.push(nativeDeclaration(input, number, 'TypeDef', 'type', match[1], {}, false));
44
+ } else if ((match = trimmed.match(/^(?:(?:private|protected|final|implicit|lazy|override|inline)\s+)*(?:val|var)\s+([A-Za-z_]\w*)\b/))) {
45
+ declarations.push(nativeDeclaration(input, number, 'ValDef', 'variable', match[1], {}, false));
46
+ }
47
+ braceDepth = Math.max(0, braceDepth + braceDelta(line));
48
+ }
49
+ return declarations;
50
+ }
51
+
52
+ function spanOptions(input, lines, index, hasBraceBody) {
53
+ return hasBraceBody ? { span: braceBlockSpan(input, lines, index) } : {};
54
+ }
55
+
56
+ function depthAfterLeadingClosers(trimmed, depth) {
57
+ const closers = String(trimmed).match(/^}+/)?.[0].length ?? 0;
58
+ return Math.max(0, depth - closers);
59
+ }
60
+
61
+ function nearestContainer(blockStack) {
62
+ for (let index = blockStack.length - 1; index >= 0; index -= 1) {
63
+ if (blockStack[index].kind === 'function') return undefined;
64
+ if (['class', 'trait', 'object', 'enum'].includes(blockStack[index].kind)) return blockStack[index];
65
+ }
66
+ return undefined;
67
+ }
68
+
69
+ function scalaContainerName(owner, kind, name) {
70
+ const base = kind === 'object' ? `${name}.object` : name;
71
+ return owner ? `${owner.name}.${base}` : base;
72
+ }
73
+
74
+ function scalaMethodTarget(owner, methodName) {
75
+ if (!owner) return { name: methodName };
76
+ const receiverKind = owner.kind === 'object' ? 'object' : 'member';
77
+ return { name: `${owner.name}.${methodName}`, owner: owner.name, receiverKind };
78
+ }
79
+
80
+ function braceDelta(source) {
81
+ return [...String(source ?? '')].reduce((delta, char) => delta + (char === '{' ? 1 : char === '}' ? -1 : 0), 0);
82
+ }
83
+
84
+ function scalaSymbolKind(kind) {
85
+ if (kind === 'trait') return 'trait';
86
+ if (kind === 'object') return 'module';
87
+ if (kind === 'enum') return 'type';
88
+ return 'class';
89
+ }
90
+
91
+ export { scanScala };
@@ -0,0 +1,74 @@
1
+ function pythonBlockSpan(input, lines, index) {
2
+ const baseIndent = indentationLength(lines[index]?.line);
3
+ let end = index;
4
+ for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
5
+ const line = lines[cursor].line;
6
+ if (line.trim() && indentationLength(line) <= baseIndent) break;
7
+ end = cursor;
8
+ }
9
+ return lineSpan(input, lines[index], lines[end] ?? lines[index]);
10
+ }
11
+
12
+ function braceBlockSpan(input, lines, index) {
13
+ let depth = 0;
14
+ let seenOpen = false;
15
+ let end = index;
16
+ for (let cursor = index; cursor < lines.length; cursor += 1) {
17
+ for (const char of lines[cursor].line) {
18
+ if (char === '{') {
19
+ seenOpen = true;
20
+ depth += 1;
21
+ } else if (char === '}') depth -= 1;
22
+ }
23
+ end = cursor;
24
+ if (seenOpen && depth <= 0) break;
25
+ }
26
+ return lineSpan(input, lines[index], lines[end] ?? lines[index]);
27
+ }
28
+
29
+ function endKeywordBlockSpan(input, lines, index) {
30
+ let depth = 0;
31
+ let end = index;
32
+ for (let cursor = index; cursor < lines.length; cursor += 1) {
33
+ const trimmed = lines[cursor].line.trim();
34
+ if (endBlockStart(trimmed)) depth += 1;
35
+ if (/^end\b/.test(trimmed)) depth -= 1;
36
+ end = cursor;
37
+ if (depth <= 0 && cursor > index) break;
38
+ }
39
+ return lineSpan(input, lines[index], lines[end] ?? lines[index]);
40
+ }
41
+
42
+ function terminatedBlockSpan(input, lines, index, terminator) {
43
+ let end = index;
44
+ for (let cursor = index; cursor < lines.length; cursor += 1) {
45
+ end = cursor;
46
+ if (terminator.test(lines[cursor].line.trim())) break;
47
+ }
48
+ return lineSpan(input, lines[index], lines[end] ?? lines[index]);
49
+ }
50
+
51
+ function sqlStatementSpan(input, lines, index) {
52
+ let end = index;
53
+ let inDollarQuote = false;
54
+ for (let cursor = index; cursor < lines.length; cursor += 1) {
55
+ const line = lines[cursor].line;
56
+ const markerCount = (line.match(/\$\$/g) ?? []).length;
57
+ if (markerCount % 2 === 1) inDollarQuote = !inDollarQuote;
58
+ end = cursor;
59
+ if (!inDollarQuote && /;\s*$/.test(line.trim())) break;
60
+ }
61
+ return lineSpan(input, lines[index], lines[end] ?? lines[index]);
62
+ }
63
+
64
+ function lineSpan(input, startLine, endLine) {
65
+ return { sourceId: input.sourceHash, path: input.sourcePath, startLine: startLine.number, endLine: endLine.number, startColumn: 1, endColumn: endLine.line.length + 1 };
66
+ }
67
+
68
+ function indentationLength(line) { return String(line ?? '').match(/^\s*/)?.[0].length ?? 0; }
69
+
70
+ function endBlockStart(line) {
71
+ return /^(?:class|module|def|defp?|defmodule|function|if|unless|case|while|for|begin|try|receive)\b/.test(line);
72
+ }
73
+
74
+ export { braceBlockSpan, endKeywordBlockSpan, pythonBlockSpan, sqlStatementSpan, terminatedBlockSpan };
@@ -0,0 +1,155 @@
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 scanSwift(input) {
6
+ const declarations = [];
7
+ const protocols = new Set();
8
+ const blockStack = [];
9
+ const lines = sourceLines(input.sourceText);
10
+ let braceDepth = 0;
11
+ for (const [index, { line, number }] of lines.entries()) {
12
+ const trimmed = line.trim();
13
+ const declarationLine = trimmed.replace(/^(?:@[A-Za-z_][\w.]+(?:\([^)]*\))?\s+)*/, '');
14
+ const lineStartDepth = depthAfterLeadingClosers(declarationLine, braceDepth);
15
+ while (blockStack.length && blockStack[blockStack.length - 1].bodyDepth > lineStartDepth) blockStack.pop();
16
+
17
+ let match;
18
+ if ((match = declarationLine.match(/^import\s+(?:(?:struct|class|enum|protocol|func|var)\s+)?([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)/))) {
19
+ declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDecl', 'module'));
20
+ } else if ((match = declarationLine.match(/^((?:(?:public|private(?:\([^)]*\))?|fileprivate|internal|open|final|indirect)\s+)*)(struct|class|enum|protocol|actor)\s+([A-Za-z_]\w*)/))) {
21
+ const owner = nearestSwiftOwner(blockStack);
22
+ const name = owner ? `${owner.name}.${match[3]}` : match[3];
23
+ if (match[2] === 'protocol') protocols.add(name);
24
+ const hasBody = declarationLine.includes('{');
25
+ declarations.push(nativeDeclaration(input, number, `${upperFirst(match[2])}Decl`, swiftSymbolKind(match[2]), name, {
26
+ modifiers: swiftModifiers(match[1]),
27
+ ...(owner ? { owner: owner.name } : {})
28
+ }, hasBody, spanOptions(input, lines, index, hasBody)));
29
+ if (hasBody) blockStack.push({ kind: swiftTypeStackKind(match[2]), name, bodyDepth: braceDepth + 1 });
30
+ } else if ((match = declarationLine.match(/^((?:(?:public|private(?:\([^)]*\))?|fileprivate|internal|open)\s+)*)extension\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)(.*)$/))) {
31
+ const extensionFields = parseSwiftExtensionTail(match[3]);
32
+ const isProtocolExtension = protocols.has(match[2]) || /Protocol$/.test(match[2]);
33
+ const receiverKind = isProtocolExtension ? 'protocolExtension' : 'extension';
34
+ const name = `${match[2]}.${receiverKind}`;
35
+ const hasBody = declarationLine.includes('{');
36
+ declarations.push(nativeDeclaration(input, number, isProtocolExtension ? 'ProtocolExtensionDecl' : 'ExtensionDecl', 'implementation', name, {
37
+ modifiers: swiftModifiers(match[1]),
38
+ extendedType: match[2],
39
+ receiverKind,
40
+ ...extensionFields
41
+ }, hasBody, spanOptions(input, lines, index, hasBody)));
42
+ if (hasBody) blockStack.push({ kind: 'extension', name, receiverKind, receiverType: match[2], bodyDepth: braceDepth + 1 });
43
+ } else if ((match = declarationLine.match(/^((?:(?:public|private(?:\([^)]*\))?|fileprivate|internal|open|static|class|mutating|nonmutating|override|required|convenience|isolated|nonisolated)\s+)*)(?:func\s+)([A-Za-z_]\w*|`[^`]+`)(?:\s*<([^>]+)>)?\s*\(([^)]*)\)/))) {
44
+ const owner = nearestSwiftOwner(blockStack);
45
+ const target = swiftMemberTarget(owner, match[1], unquoteSwiftIdentifier(match[2]));
46
+ const hasBody = declarationLine.includes('{');
47
+ declarations.push(nativeDeclaration(input, number, 'FunctionDecl', target.owner ? 'method' : 'function', target.name, {
48
+ methodName: unquoteSwiftIdentifier(match[2]),
49
+ modifiers: swiftModifiers(match[1]),
50
+ typeParameters: splitTypeParameters(match[3]),
51
+ parameters: splitParameters(match[4]),
52
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind, receiverType: target.receiverType } : {})
53
+ }, hasBody, memberSpanOptions(input, lines, index, hasBody, target, unquoteSwiftIdentifier(match[2]), match[1])));
54
+ if (hasBody) blockStack.push({ kind: 'method', name: target.name, bodyDepth: braceDepth + 1 });
55
+ } else if ((match = declarationLine.match(/^((?:(?:public|private(?:\([^)]*\))?|fileprivate|internal|open|static|class|final|lazy|weak|unowned|override|required|nonisolated)\s+)*)(let|var)\s+([A-Za-z_]\w*)\b(?::\s*([^={]+))?/))) {
56
+ const owner = nearestSwiftOwner(blockStack);
57
+ const target = swiftMemberTarget(owner, match[1], match[3]);
58
+ const hasBody = declarationLine.includes('{') || declarationLine.includes('=>');
59
+ declarations.push(nativeDeclaration(input, number, 'PropertyDecl', 'property', target.name, {
60
+ binding: match[2],
61
+ modifiers: swiftModifiers(match[1]),
62
+ valueType: match[4]?.trim(),
63
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind, receiverType: target.receiverType } : {})
64
+ }, hasBody, memberSpanOptions(input, lines, index, hasBody, target, match[3], match[1])));
65
+ } else if ((match = declarationLine.match(/^(?:(?:public|private(?:\([^)]*\))?|fileprivate|internal|open)\s+)*typealias\s+([A-Za-z_]\w*)\b(?:\s*=\s*(.+))?/))) {
66
+ const owner = nearestSwiftOwner(blockStack);
67
+ const name = owner ? `${owner.name}.${match[1]}` : match[1];
68
+ declarations.push(nativeDeclaration(input, number, 'TypealiasDecl', 'type', name, {
69
+ target: match[2]?.trim(),
70
+ ...(owner ? { owner: owner.name } : {})
71
+ }, false));
72
+ }
73
+ braceDepth = Math.max(0, braceDepth + braceDelta(line));
74
+ }
75
+ return declarations;
76
+ }
77
+
78
+ function spanOptions(input, lines, index, hasBraceBody) {
79
+ return hasBraceBody ? { span: braceBlockSpan(input, lines, index) } : {};
80
+ }
81
+
82
+ function memberSpanOptions(input, lines, index, hasBody, target, methodName, modifiers) {
83
+ return {
84
+ ...spanOptions(input, lines, index, hasBody),
85
+ metadata: {
86
+ methodName,
87
+ modifiers: swiftModifiers(modifiers),
88
+ ...(target.owner ? { owner: target.owner, receiverKind: target.receiverKind, receiverType: target.receiverType } : {})
89
+ }
90
+ };
91
+ }
92
+
93
+ function depthAfterLeadingClosers(trimmed, depth) {
94
+ const closers = String(trimmed).match(/^}+/)?.[0].length ?? 0;
95
+ return Math.max(0, depth - closers);
96
+ }
97
+
98
+ function nearestSwiftOwner(blockStack) {
99
+ for (let index = blockStack.length - 1; index >= 0; index -= 1) {
100
+ if (blockStack[index].kind === 'method') return undefined;
101
+ if (['actor', 'class', 'enum', 'extension', 'protocol', 'struct'].includes(blockStack[index].kind)) return blockStack[index];
102
+ }
103
+ return undefined;
104
+ }
105
+
106
+ function swiftMemberTarget(owner, modifiers, memberName) {
107
+ if (!owner) return { name: memberName };
108
+ if (owner.kind === 'extension') {
109
+ if (/\b(?:static|class)\b/.test(modifiers)) {
110
+ return { name: `${owner.name}.static.${memberName}`, owner: owner.name, receiverKind: 'static', receiverType: owner.receiverType };
111
+ }
112
+ return { name: `${owner.name}.${memberName}`, owner: owner.name, receiverKind: owner.receiverKind, receiverType: owner.receiverType };
113
+ }
114
+ const receiverKind = /\b(?:static|class)\b/.test(modifiers) ? 'static' : 'member';
115
+ return { name: receiverKind === 'static' ? `${owner.name}.static.${memberName}` : `${owner.name}.${memberName}`, owner: owner.name, receiverKind };
116
+ }
117
+
118
+ function swiftModifiers(raw) {
119
+ return splitParameters(String(raw ?? '').trim().replace(/\s+/g, ','));
120
+ }
121
+
122
+ function swiftTypeStackKind(kind) {
123
+ return String(kind).replace(/\s+/g, ' ');
124
+ }
125
+
126
+ function braceDelta(source) {
127
+ return [...String(source ?? '')].reduce((delta, char) => delta + (char === '{' ? 1 : char === '}' ? -1 : 0), 0);
128
+ }
129
+
130
+ function parseSwiftExtensionTail(rawTail) {
131
+ let tail = String(rawTail ?? '').split('{')[0].trim();
132
+ const fields = {};
133
+ const whereMatch = tail.match(/\bwhere\b(.+)$/);
134
+ if (whereMatch) {
135
+ fields.constraints = whereMatch[1].trim();
136
+ tail = tail.slice(0, whereMatch.index).trim();
137
+ }
138
+ if (tail.startsWith(':')) {
139
+ fields.conformances = tail.slice(1).split(',').map((part) => part.trim()).filter(Boolean);
140
+ }
141
+ return fields;
142
+ }
143
+
144
+ function unquoteSwiftIdentifier(identifier) {
145
+ return String(identifier).replace(/^`|`$/g, '');
146
+ }
147
+
148
+ function swiftSymbolKind(kind) {
149
+ if (kind === 'protocol') return 'protocol';
150
+ if (kind === 'extension') return 'implementation';
151
+ if (kind === 'struct' || kind === 'enum' || kind === 'actor') return 'type';
152
+ return 'class';
153
+ }
154
+
155
+ export { scanSwift };
@@ -1,24 +1,24 @@
1
1
  import { scanJavaScriptLike } from './native-region-scanner-js.js';
2
2
  import {
3
3
  scanCLike,
4
- scanCSharp,
5
4
  scanGo,
6
- scanJava,
7
- scanPython,
8
- scanRust,
9
- scanSwift
5
+ scanRust
10
6
  } from './native-region-scanner-main.js';
7
+ import { scanJava } from './native-region-scanner-java.js';
8
+ import { scanSwift } from './native-region-scanner-swift.js';
9
+ import { scanCSharp } from './native-region-scanner-csharp.js';
10
+ import { scanPython } from './native-region-scanner-python.js';
11
+ import { scanPhp } from './native-region-scanner-php.js';
12
+ import { scanKotlin } from './native-region-scanner-kotlin.js';
13
+ import { scanScala } from './native-region-scanner-scala.js';
14
+ import { scanDart } from './native-region-scanner-dart.js';
11
15
  import {
12
- scanDart,
13
- scanKotlin,
14
16
  scanLua,
15
- scanPhp,
16
- scanRuby,
17
- scanScala,
18
17
  scanShell,
19
18
  scanSql,
20
19
  scanZig
21
20
  } from './native-region-scanner-dynamic.js';
21
+ import { scanRuby } from './native-region-scanner-ruby.js';
22
22
  import {
23
23
  scanElixir,
24
24
  scanErlang,
@@ -33,6 +33,10 @@ export {
33
33
  scanPreservedSourceDirectives,
34
34
  scanPreservedSourceTokens
35
35
  } from './native-source-preservation-scanner.js';
36
+ export {
37
+ isJavaScriptTypeScriptSource,
38
+ scanJavaScriptTypeScriptSourceLedger
39
+ } from './native-source-ledger.js';
36
40
 
37
41
  function scanNativeDeclarations(input) {
38
42
  const language = normalizeNativeLanguageId(input.language) || String(input.language).toLowerCase();