@shapeshift-labs/frontier-lang-compiler 0.2.23 → 0.2.25
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 +24 -2
- package/bench/smoke.mjs +53 -0
- package/dist/index.d.ts +95 -1
- package/dist/index.js +487 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -191,10 +191,30 @@ const imported = importNativeSource({
|
|
|
191
191
|
const sidecar = createSemanticImportSidecar(imported);
|
|
192
192
|
|
|
193
193
|
console.log(sidecar.summary.emptySemanticIndex); // false when symbols were found
|
|
194
|
-
console.log(sidecar.ownershipRegions[0].key); // source#src/runtime.ts#
|
|
194
|
+
console.log(sidecar.ownershipRegions[0].key); // source#src/runtime.ts#type#Runtime
|
|
195
195
|
console.log(sidecar.patchHints[0].supportedOperations); // source-region patch operations
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
The built-in JavaScript/TypeScript lightweight scanner also emits review-required ownership regions for clear route/config/content/property shapes in exported objects and arrays:
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
const importedConfig = importNativeSource({
|
|
202
|
+
language: 'typescript',
|
|
203
|
+
sourcePath: 'src/routes.ts',
|
|
204
|
+
sourceText: `
|
|
205
|
+
export const appRoutes = [
|
|
206
|
+
{ path: "/home", component: Home }
|
|
207
|
+
];
|
|
208
|
+
export const siteContent = {
|
|
209
|
+
docs: { title: "Docs" }
|
|
210
|
+
};
|
|
211
|
+
`
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const configSidecar = createSemanticImportSidecar(importedConfig);
|
|
215
|
+
console.log(configSidecar.regionTaxonomy.presentKinds); // includes "route" and "content"
|
|
216
|
+
```
|
|
217
|
+
|
|
198
218
|
Compare before/after native source imports from a worker patch and emit a semantic change set for admission scoring:
|
|
199
219
|
|
|
200
220
|
```js
|
|
@@ -209,10 +229,12 @@ const changeSet = diffNativeSources({
|
|
|
209
229
|
|
|
210
230
|
console.log(changeSet.changedSymbols[0]?.changeKind); // "modified"
|
|
211
231
|
console.log(changeSet.changedRegions[0]?.conflictKey); // semantic ownership key
|
|
232
|
+
console.log(changeSet.changedRegions[0]?.metadata.changedRegionProjection.reviewRequired); // true
|
|
233
|
+
console.log(changeSet.metadata.changedRegionProjectionSummary.autoMergeClaims); // 0
|
|
212
234
|
console.log(changeSet.mergeCandidate.readiness); // merge-admission classification
|
|
213
235
|
```
|
|
214
236
|
|
|
215
|
-
Use `diffNativeSourceImports` when the worker or runner already produced `importNativeSource` results. Body-only edits that the lightweight scanner cannot anchor to a symbol are still reported as file-level changed regions instead of being silently treated as safe.
|
|
237
|
+
Use `diffNativeSourceImports` when the worker or runner already produced `importNativeSource` results. Changed regions include a `metadata.changedRegionProjection` envelope with before/after source hashes, source-map links, ownership keys, readiness, and `autoMergeClaim: false` so swarm admission tools can score or port patches without treating semantic metadata as proof. Body-only edits that the lightweight scanner cannot anchor to a symbol are still reported as file-level changed regions instead of being silently treated as safe.
|
|
216
238
|
|
|
217
239
|
Compile native source imports through the same reader/IR/writer facade that swarms use for sidecar evidence. Same-language targets preserve exact source when hashes match; cross-language targets emit declaration stubs until a real adapter provides stronger evidence:
|
|
218
240
|
|
package/bench/smoke.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
createProjectionTargetLossMatrix,
|
|
8
8
|
createNativeSourcePreservation,
|
|
9
9
|
createSemanticImportSidecar,
|
|
10
|
+
diffNativeSources,
|
|
10
11
|
importExternalSemanticIndex,
|
|
11
12
|
importNativeSource,
|
|
12
13
|
projectNativeImportToSource,
|
|
@@ -135,6 +136,50 @@ const nativeTargetAdapterDurationMs = performance.now() - nativeTargetAdapterSta
|
|
|
135
136
|
const nativeTargetAdapterBytes = nativeTargetAdapterCompiles.reduce((sum, result) => sum + result.output.length, 0);
|
|
136
137
|
const nativeTargetAdapterSourceMaps = nativeTargetAdapterCompiles.reduce((sum, result) => sum + result.sourceMaps.length, 0);
|
|
137
138
|
|
|
139
|
+
const regionScanStart = performance.now();
|
|
140
|
+
const regionScanImports = [];
|
|
141
|
+
for (let index = 0; index < 100; index += 1) {
|
|
142
|
+
const imported = importNativeSource({
|
|
143
|
+
language: 'typescript',
|
|
144
|
+
sourcePath: `src/regions-${index}.ts`,
|
|
145
|
+
sourceText: `
|
|
146
|
+
export const appRoutes${index} = [
|
|
147
|
+
{ path: "/${index}", component: Screen${index} },
|
|
148
|
+
{ path: "/${index}/settings", component: Settings${index} }
|
|
149
|
+
];
|
|
150
|
+
export const contentBlocks${index} = {
|
|
151
|
+
docs: { title: "Docs ${index}" },
|
|
152
|
+
legal: { title: "Legal ${index}" }
|
|
153
|
+
};
|
|
154
|
+
export const runtimeConfig${index} = {
|
|
155
|
+
limits: { count: ${index} },
|
|
156
|
+
resolve(id) { return id; }
|
|
157
|
+
};
|
|
158
|
+
export const helpers${index} = {
|
|
159
|
+
plain: ${index}
|
|
160
|
+
};
|
|
161
|
+
`
|
|
162
|
+
});
|
|
163
|
+
regionScanImports.push({ imported, sidecar: createSemanticImportSidecar(imported) });
|
|
164
|
+
}
|
|
165
|
+
const regionScanDurationMs = performance.now() - regionScanStart;
|
|
166
|
+
const regionScanSymbols = regionScanImports.reduce((sum, entry) => sum + entry.imported.semanticIndex.symbols.length, 0);
|
|
167
|
+
const regionScanOwnershipRegions = regionScanImports.reduce((sum, entry) => sum + entry.sidecar.ownershipRegions.length, 0);
|
|
168
|
+
|
|
169
|
+
const changeProjectionStart = performance.now();
|
|
170
|
+
const changeProjectionSets = [];
|
|
171
|
+
for (let index = 0; index < 80; index += 1) {
|
|
172
|
+
changeProjectionSets.push(diffNativeSources({
|
|
173
|
+
language: 'javascript',
|
|
174
|
+
sourcePath: `src/change-projection-${index}.js`,
|
|
175
|
+
beforeSourceText: `export function changeProjection${index}() { return ${index}; }\n`,
|
|
176
|
+
afterSourceText: `export function changeProjection${index}() { return ${index + 1}; }\nexport const changeProjectionFlag${index} = true;\n`
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
const changeProjectionDurationMs = performance.now() - changeProjectionStart;
|
|
180
|
+
const changedRegionProjections = changeProjectionSets.reduce((sum, changeSet) => sum + changeSet.metadata.changedRegionProjectionSummary.withProjection, 0);
|
|
181
|
+
const changedRegionProjectionSourceMapLinks = changeProjectionSets.reduce((sum, changeSet) => sum + changeSet.metadata.changedRegionProjectionSummary.sourceMapLinks, 0);
|
|
182
|
+
|
|
138
183
|
const externalSemanticStart = performance.now();
|
|
139
184
|
const externalSemanticImports = [];
|
|
140
185
|
for (let index = 0; index < 100; index += 1) {
|
|
@@ -208,6 +253,14 @@ console.log(JSON.stringify({
|
|
|
208
253
|
nativeTargetAdapterBytes,
|
|
209
254
|
nativeTargetAdapterSourceMaps,
|
|
210
255
|
nativeTargetAdapterDurationMs: Number(nativeTargetAdapterDurationMs.toFixed(2)),
|
|
256
|
+
regionScanImports: regionScanImports.length,
|
|
257
|
+
regionScanSymbols,
|
|
258
|
+
regionScanOwnershipRegions,
|
|
259
|
+
regionScanDurationMs: Number(regionScanDurationMs.toFixed(2)),
|
|
260
|
+
changeProjectionSets: changeProjectionSets.length,
|
|
261
|
+
changedRegionProjections,
|
|
262
|
+
changedRegionProjectionSourceMapLinks,
|
|
263
|
+
changeProjectionDurationMs: Number(changeProjectionDurationMs.toFixed(2)),
|
|
211
264
|
externalSemanticImports: externalSemanticImports.length,
|
|
212
265
|
externalSemanticSymbols,
|
|
213
266
|
externalSemanticMappings,
|
package/dist/index.d.ts
CHANGED
|
@@ -140,6 +140,10 @@ export type NativeImportRegionTaxonomyKind =
|
|
|
140
140
|
| 'call'
|
|
141
141
|
| 'type'
|
|
142
142
|
| 'effect'
|
|
143
|
+
| 'property'
|
|
144
|
+
| 'config'
|
|
145
|
+
| 'content'
|
|
146
|
+
| 'route'
|
|
143
147
|
| 'generatedOutput'
|
|
144
148
|
| string;
|
|
145
149
|
|
|
@@ -782,6 +786,91 @@ export interface SemanticImportSidecarOptions {
|
|
|
782
786
|
|
|
783
787
|
export type NativeSourceChangeKind = 'added' | 'removed' | 'modified' | 'unchanged';
|
|
784
788
|
|
|
789
|
+
export interface NativeSourceChangeProjectionEndpoint {
|
|
790
|
+
readonly side: 'before' | 'after';
|
|
791
|
+
readonly importId?: string;
|
|
792
|
+
readonly sidecarId?: string;
|
|
793
|
+
readonly nativeSourceId?: string;
|
|
794
|
+
readonly nativeAstId?: string;
|
|
795
|
+
readonly semanticIndexId?: string;
|
|
796
|
+
readonly universalAstId?: string;
|
|
797
|
+
readonly sourcePath?: string;
|
|
798
|
+
readonly sourceHash?: string;
|
|
799
|
+
readonly sourcePreservationId?: string;
|
|
800
|
+
readonly exactSourceAvailable: boolean;
|
|
801
|
+
readonly ownershipRegionId?: string;
|
|
802
|
+
readonly ownershipKey?: string;
|
|
803
|
+
readonly ownershipRegionKind?: NativeImportRegionTaxonomyKind;
|
|
804
|
+
readonly sourceSpan?: SourceSpan;
|
|
805
|
+
readonly sourceMapIds: readonly string[];
|
|
806
|
+
readonly sourceMapMappingIds: readonly string[];
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export interface NativeSourceChangeProjectionSourceMapLink {
|
|
810
|
+
readonly id: string;
|
|
811
|
+
readonly side: 'before' | 'after';
|
|
812
|
+
readonly sourceMapId?: string;
|
|
813
|
+
readonly sourceMapMappingId?: string;
|
|
814
|
+
readonly sourcePath?: string;
|
|
815
|
+
readonly sourceHash?: string;
|
|
816
|
+
readonly targetPath?: string;
|
|
817
|
+
readonly targetHash?: string;
|
|
818
|
+
readonly semanticSymbolId?: string;
|
|
819
|
+
readonly semanticOccurrenceId?: string;
|
|
820
|
+
readonly semanticNodeId?: string;
|
|
821
|
+
readonly nativeSourceId?: string;
|
|
822
|
+
readonly nativeAstNodeId?: string;
|
|
823
|
+
readonly precision?: string;
|
|
824
|
+
readonly sourceSpan?: SourceSpan;
|
|
825
|
+
readonly generatedSpan?: SourceMapMappingRecord['generatedSpan'];
|
|
826
|
+
readonly ownershipRegionId?: string;
|
|
827
|
+
readonly ownershipRegionKey?: string;
|
|
828
|
+
readonly ownershipRegionKind?: NativeImportRegionTaxonomyKind;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
export interface NativeSourceChangeProjectionMetadata {
|
|
832
|
+
readonly schema: 'frontier.lang.changedRegionProjection.v1';
|
|
833
|
+
readonly id: string;
|
|
834
|
+
readonly reviewRequired: true;
|
|
835
|
+
readonly autoMergeClaim: false;
|
|
836
|
+
readonly changeKind: NativeSourceChangeKind;
|
|
837
|
+
readonly language?: FrontierSourceLanguage | string;
|
|
838
|
+
readonly sourcePath?: string;
|
|
839
|
+
readonly conflictKey: string;
|
|
840
|
+
readonly region: {
|
|
841
|
+
readonly id?: string;
|
|
842
|
+
readonly key?: string;
|
|
843
|
+
readonly kind?: NativeImportRegionTaxonomyKind;
|
|
844
|
+
readonly granularity?: string;
|
|
845
|
+
readonly precision?: string;
|
|
846
|
+
readonly sourceSpan?: SourceSpan;
|
|
847
|
+
readonly nativeAstNodeId?: string;
|
|
848
|
+
readonly symbolId?: string;
|
|
849
|
+
readonly symbolName?: string;
|
|
850
|
+
readonly symbolKind?: string;
|
|
851
|
+
};
|
|
852
|
+
readonly before?: NativeSourceChangeProjectionEndpoint;
|
|
853
|
+
readonly after?: NativeSourceChangeProjectionEndpoint;
|
|
854
|
+
readonly sourceMapLinks: readonly NativeSourceChangeProjectionSourceMapLink[];
|
|
855
|
+
readonly admission: {
|
|
856
|
+
readonly readiness: SemanticMergeReadiness;
|
|
857
|
+
readonly action: 'review-addition' | 'review-removal' | 'review-file' | 'review-port' | 'rerun-or-human-port' | string;
|
|
858
|
+
readonly reasons: readonly string[];
|
|
859
|
+
readonly conflictKeys: readonly string[];
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
export interface NativeSourceChangeProjectionSummary {
|
|
864
|
+
readonly schema: 'frontier.lang.changedRegionProjectionSummary.v1';
|
|
865
|
+
readonly total: number;
|
|
866
|
+
readonly withProjection: number;
|
|
867
|
+
readonly reviewRequired: number;
|
|
868
|
+
readonly autoMergeClaims: number;
|
|
869
|
+
readonly sourceMapLinks: number;
|
|
870
|
+
readonly byAction: Readonly<Record<string, number>>;
|
|
871
|
+
readonly byRegionKind: Readonly<Record<string, number>>;
|
|
872
|
+
}
|
|
873
|
+
|
|
785
874
|
export interface NativeSourceChangeSymbol {
|
|
786
875
|
readonly changeKind: NativeSourceChangeKind;
|
|
787
876
|
readonly key: string;
|
|
@@ -809,6 +898,9 @@ export interface NativeSourceChangeSymbol {
|
|
|
809
898
|
export interface NativeSourceChangeRegion extends SemanticImportOwnershipRegion {
|
|
810
899
|
readonly changeKind: NativeSourceChangeKind;
|
|
811
900
|
readonly conflictKey: string;
|
|
901
|
+
readonly metadata?: SemanticImportOwnershipRegion['metadata'] & {
|
|
902
|
+
readonly changedRegionProjection?: NativeSourceChangeProjectionMetadata;
|
|
903
|
+
};
|
|
812
904
|
}
|
|
813
905
|
|
|
814
906
|
export interface NativeSourceChangeSummary {
|
|
@@ -871,7 +963,9 @@ export interface NativeSourceChangeSet {
|
|
|
871
963
|
readonly semanticIndex?: SemanticIndexRecord;
|
|
872
964
|
readonly losses: readonly NativeAstLossRecord[];
|
|
873
965
|
readonly summary: NativeSourceChangeSummary;
|
|
874
|
-
readonly metadata?: Record<string, unknown
|
|
966
|
+
readonly metadata?: Record<string, unknown> & {
|
|
967
|
+
readonly changedRegionProjectionSummary?: NativeSourceChangeProjectionSummary;
|
|
968
|
+
};
|
|
875
969
|
}
|
|
876
970
|
|
|
877
971
|
export type NativeImporterAdapterExactness =
|
package/dist/index.js
CHANGED
|
@@ -262,6 +262,10 @@ export const NativeImportRegionTaxonomyKinds = Object.freeze([
|
|
|
262
262
|
'call',
|
|
263
263
|
'type',
|
|
264
264
|
'effect',
|
|
265
|
+
'property',
|
|
266
|
+
'config',
|
|
267
|
+
'content',
|
|
268
|
+
'route',
|
|
265
269
|
'generatedOutput'
|
|
266
270
|
]);
|
|
267
271
|
|
|
@@ -3154,6 +3158,25 @@ export function diffNativeSourceImports(input) {
|
|
|
3154
3158
|
if (sourceChanged && changedSymbols.length === 0 && changedRegions.length === 0) {
|
|
3155
3159
|
changedRegions = [fileLevelNativeChangeRegion({ language, sourcePath, beforeHash, afterHash, before, after })];
|
|
3156
3160
|
}
|
|
3161
|
+
const readiness = maxSemanticMergeReadiness(
|
|
3162
|
+
maxSemanticMergeReadiness(nativeImportReadiness(before), nativeImportReadiness(after)),
|
|
3163
|
+
sourceChanged && changedSymbols.length === 0 ? 'needs-review' : 'ready'
|
|
3164
|
+
);
|
|
3165
|
+
const reasons = nativeSourceChangeReasons({ before, after, beforeHash, afterHash, changedSymbols, changedRegions, readiness });
|
|
3166
|
+
changedRegions = attachNativeChangeRegionProjectionMetadata(changedRegions, {
|
|
3167
|
+
before,
|
|
3168
|
+
after,
|
|
3169
|
+
beforeSidecar,
|
|
3170
|
+
afterSidecar,
|
|
3171
|
+
changedSymbols,
|
|
3172
|
+
language,
|
|
3173
|
+
sourcePath,
|
|
3174
|
+
beforeHash,
|
|
3175
|
+
afterHash,
|
|
3176
|
+
readiness,
|
|
3177
|
+
reasons
|
|
3178
|
+
});
|
|
3179
|
+
const changedRegionProjectionSummary = summarizeNativeChangedRegionProjections(changedRegions);
|
|
3157
3180
|
const evidence = [{
|
|
3158
3181
|
id: input.evidenceId ?? `evidence_${idPart}_native_source_diff`,
|
|
3159
3182
|
kind: 'import',
|
|
@@ -3168,14 +3191,10 @@ export function diffNativeSourceImports(input) {
|
|
|
3168
3191
|
sourceChanged,
|
|
3169
3192
|
addedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'added').length,
|
|
3170
3193
|
removedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'removed').length,
|
|
3171
|
-
modifiedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'modified').length
|
|
3194
|
+
modifiedSymbols: changedSymbols.filter((symbol) => symbol.changeKind === 'modified').length,
|
|
3195
|
+
changedRegionProjectionSummary
|
|
3172
3196
|
}
|
|
3173
3197
|
}];
|
|
3174
|
-
const readiness = maxSemanticMergeReadiness(
|
|
3175
|
-
maxSemanticMergeReadiness(nativeImportReadiness(before), nativeImportReadiness(after)),
|
|
3176
|
-
sourceChanged && changedSymbols.length === 0 ? 'needs-review' : 'ready'
|
|
3177
|
-
);
|
|
3178
|
-
const reasons = nativeSourceChangeReasons({ before, after, beforeHash, afterHash, changedSymbols, changedRegions, readiness });
|
|
3179
3198
|
const conflictKeys = uniqueStrings([
|
|
3180
3199
|
...changedSymbols.map((symbol) => symbol.conflictKey),
|
|
3181
3200
|
...changedRegions.map((region) => region.conflictKey ?? region.key ?? region.id),
|
|
@@ -3226,7 +3245,8 @@ export function diffNativeSourceImports(input) {
|
|
|
3226
3245
|
beforeImportId: before?.id,
|
|
3227
3246
|
afterImportId: after?.id,
|
|
3228
3247
|
sourceChanged,
|
|
3229
|
-
changeSummary: nativeSourceChangeSummary(changedSymbols, changedRegions, sourceChanged)
|
|
3248
|
+
changeSummary: nativeSourceChangeSummary(changedSymbols, changedRegions, sourceChanged),
|
|
3249
|
+
changedRegionProjectionSummary
|
|
3230
3250
|
}
|
|
3231
3251
|
});
|
|
3232
3252
|
return {
|
|
@@ -3255,6 +3275,7 @@ export function diffNativeSourceImports(input) {
|
|
|
3255
3275
|
afterSidecarId: afterSidecar?.id,
|
|
3256
3276
|
beforeImportContract: before?.metadata?.importResultContract,
|
|
3257
3277
|
afterImportContract: after?.metadata?.importResultContract,
|
|
3278
|
+
changedRegionProjectionSummary,
|
|
3258
3279
|
...input.metadata
|
|
3259
3280
|
}
|
|
3260
3281
|
};
|
|
@@ -3400,6 +3421,199 @@ function fileLevelNativeChangeRegion(input) {
|
|
|
3400
3421
|
};
|
|
3401
3422
|
}
|
|
3402
3423
|
|
|
3424
|
+
function attachNativeChangeRegionProjectionMetadata(regions, context) {
|
|
3425
|
+
return (regions ?? []).map((region) => {
|
|
3426
|
+
const projection = nativeChangedRegionProjectionMetadata(region, context);
|
|
3427
|
+
return {
|
|
3428
|
+
...region,
|
|
3429
|
+
metadata: {
|
|
3430
|
+
...(region.metadata ?? {}),
|
|
3431
|
+
changedRegionProjection: projection
|
|
3432
|
+
}
|
|
3433
|
+
};
|
|
3434
|
+
});
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
function nativeChangedRegionProjectionMetadata(region, context) {
|
|
3438
|
+
const beforeRegion = findSemanticImportRegion(context.beforeSidecar, region);
|
|
3439
|
+
const afterRegion = findSemanticImportRegion(context.afterSidecar, region);
|
|
3440
|
+
const regionSymbols = (context.changedSymbols ?? []).filter((symbol) => nativeChangeSymbolTouchesRegion(symbol, region));
|
|
3441
|
+
const sourceMapLinks = uniqueRecordsById([
|
|
3442
|
+
...nativeChangeProjectionSourceMapLinks(context.before, 'before', beforeRegion ?? region, regionSymbols),
|
|
3443
|
+
...nativeChangeProjectionSourceMapLinks(context.after, 'after', afterRegion ?? region, regionSymbols)
|
|
3444
|
+
]).slice(0, 24);
|
|
3445
|
+
const action = nativeChangedRegionProjectionAction(region, context.readiness);
|
|
3446
|
+
const conflictKeys = uniqueStrings([
|
|
3447
|
+
region.conflictKey,
|
|
3448
|
+
region.key ? `region:${region.key}` : undefined,
|
|
3449
|
+
region.id ? `region:${region.id}` : undefined,
|
|
3450
|
+
...regionSymbols.map((symbol) => symbol.conflictKey)
|
|
3451
|
+
].filter(Boolean));
|
|
3452
|
+
return {
|
|
3453
|
+
schema: 'frontier.lang.changedRegionProjection.v1',
|
|
3454
|
+
id: `changed_region_projection_${idFragment(region.conflictKey ?? region.key ?? region.id)}`,
|
|
3455
|
+
reviewRequired: true,
|
|
3456
|
+
autoMergeClaim: false,
|
|
3457
|
+
changeKind: region.changeKind,
|
|
3458
|
+
language: region.language ?? context.language,
|
|
3459
|
+
sourcePath: region.sourcePath ?? context.sourcePath,
|
|
3460
|
+
conflictKey: region.conflictKey,
|
|
3461
|
+
region: {
|
|
3462
|
+
id: region.id,
|
|
3463
|
+
key: region.key,
|
|
3464
|
+
kind: region.regionKind,
|
|
3465
|
+
granularity: region.granularity,
|
|
3466
|
+
precision: region.precision,
|
|
3467
|
+
sourceSpan: region.sourceSpan,
|
|
3468
|
+
nativeAstNodeId: region.nativeAstNodeId,
|
|
3469
|
+
symbolId: region.symbolId,
|
|
3470
|
+
symbolName: region.symbolName,
|
|
3471
|
+
symbolKind: region.symbolKind
|
|
3472
|
+
},
|
|
3473
|
+
before: nativeChangeProjectionEndpoint(context.before, context.beforeSidecar, beforeRegion ?? (region.changeKind === 'added' ? undefined : region), 'before'),
|
|
3474
|
+
after: nativeChangeProjectionEndpoint(context.after, context.afterSidecar, afterRegion ?? (region.changeKind === 'removed' ? undefined : region), 'after'),
|
|
3475
|
+
sourceMapLinks,
|
|
3476
|
+
admission: {
|
|
3477
|
+
readiness: context.readiness,
|
|
3478
|
+
action,
|
|
3479
|
+
reasons: context.reasons ?? [],
|
|
3480
|
+
conflictKeys
|
|
3481
|
+
}
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3485
|
+
function findSemanticImportRegion(sidecar, region) {
|
|
3486
|
+
return (sidecar?.ownershipRegions ?? []).find((candidate) => (
|
|
3487
|
+
(region.id && candidate.id === region.id) ||
|
|
3488
|
+
(region.key && candidate.key === region.key)
|
|
3489
|
+
));
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3492
|
+
function nativeChangeProjectionEndpoint(imported, sidecar, region, side) {
|
|
3493
|
+
if (!imported && !region) return undefined;
|
|
3494
|
+
const preservation = nativeImportSourcePreservationRecord(imported);
|
|
3495
|
+
const sourceMaps = imported?.sourceMaps ?? imported?.universalAst?.sourceMaps ?? [];
|
|
3496
|
+
const regionMappings = sourceMaps
|
|
3497
|
+
.flatMap((sourceMap) => (sourceMap?.mappings ?? []).map((mapping) => ({ sourceMap, mapping })))
|
|
3498
|
+
.filter(({ mapping }) => nativeChangeMappingTouchesRegion(mapping, region, []));
|
|
3499
|
+
return {
|
|
3500
|
+
side,
|
|
3501
|
+
importId: imported?.id,
|
|
3502
|
+
sidecarId: sidecar?.id,
|
|
3503
|
+
nativeSourceId: imported?.nativeSource?.id,
|
|
3504
|
+
nativeAstId: imported?.nativeAst?.id,
|
|
3505
|
+
semanticIndexId: imported?.semanticIndex?.id,
|
|
3506
|
+
universalAstId: imported?.universalAst?.id,
|
|
3507
|
+
sourcePath: imported?.sourcePath ?? region?.sourcePath,
|
|
3508
|
+
sourceHash: imported?.nativeSource?.sourceHash ?? imported?.nativeAst?.sourceHash ?? region?.sourceHash,
|
|
3509
|
+
sourcePreservationId: preservation?.id,
|
|
3510
|
+
exactSourceAvailable: preservation?.summary?.exactSourceAvailable === true,
|
|
3511
|
+
ownershipRegionId: region?.id,
|
|
3512
|
+
ownershipKey: region?.key,
|
|
3513
|
+
ownershipRegionKind: region?.regionKind,
|
|
3514
|
+
sourceSpan: region?.sourceSpan,
|
|
3515
|
+
sourceMapIds: sourceMaps.map((sourceMap) => sourceMap?.id).filter(Boolean),
|
|
3516
|
+
sourceMapMappingIds: regionMappings.map(({ mapping }) => mapping?.id).filter(Boolean)
|
|
3517
|
+
};
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3520
|
+
function nativeChangeProjectionSourceMapLinks(imported, side, region, symbols) {
|
|
3521
|
+
if (!imported) return [];
|
|
3522
|
+
const sourceMaps = imported.sourceMaps ?? imported.universalAst?.sourceMaps ?? [];
|
|
3523
|
+
const links = [];
|
|
3524
|
+
for (const sourceMap of sourceMaps) {
|
|
3525
|
+
for (const mapping of sourceMap?.mappings ?? []) {
|
|
3526
|
+
if (!nativeChangeMappingTouchesRegion(mapping, region, symbols)) continue;
|
|
3527
|
+
links.push({
|
|
3528
|
+
id: `${side}:${sourceMap.id}:${mapping.id}`,
|
|
3529
|
+
side,
|
|
3530
|
+
sourceMapId: sourceMap.id,
|
|
3531
|
+
sourceMapMappingId: mapping.id,
|
|
3532
|
+
sourcePath: mapping.sourceSpan?.path ?? sourceMap.sourcePath ?? imported.sourcePath,
|
|
3533
|
+
sourceHash: sourceMap.sourceHash ?? imported.nativeSource?.sourceHash ?? imported.nativeAst?.sourceHash,
|
|
3534
|
+
targetPath: mapping.generatedSpan?.targetPath ?? sourceMap.targetPath,
|
|
3535
|
+
targetHash: mapping.generatedSpan?.targetHash ?? sourceMap.targetHash,
|
|
3536
|
+
semanticSymbolId: mapping.semanticSymbolId,
|
|
3537
|
+
semanticOccurrenceId: mapping.semanticOccurrenceId,
|
|
3538
|
+
semanticNodeId: mapping.semanticNodeId,
|
|
3539
|
+
nativeSourceId: mapping.nativeSourceId,
|
|
3540
|
+
nativeAstNodeId: mapping.nativeAstNodeId,
|
|
3541
|
+
precision: mapping.precision,
|
|
3542
|
+
sourceSpan: mapping.sourceSpan,
|
|
3543
|
+
generatedSpan: mapping.generatedSpan,
|
|
3544
|
+
ownershipRegionId: mapping.ownershipRegionId,
|
|
3545
|
+
ownershipRegionKey: mapping.ownershipRegionKey,
|
|
3546
|
+
ownershipRegionKind: mapping.ownershipRegionKind
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
return links;
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3553
|
+
function nativeChangeMappingTouchesRegion(mapping, region, symbols) {
|
|
3554
|
+
if (!mapping || !region) return false;
|
|
3555
|
+
const symbolIds = new Set((symbols ?? []).map((symbol) => symbol.id).filter(Boolean));
|
|
3556
|
+
const occurrenceIds = new Set((symbols ?? []).map((symbol) => symbol.semanticOccurrenceId).filter(Boolean));
|
|
3557
|
+
const mappingIds = new Set((symbols ?? []).map((symbol) => symbol.sourceMapMappingId).filter(Boolean));
|
|
3558
|
+
if (mappingIds.has(mapping.id)) return true;
|
|
3559
|
+
if (region.id && mapping.ownershipRegionId === region.id) return true;
|
|
3560
|
+
if (region.key && mapping.ownershipRegionKey === region.key) return true;
|
|
3561
|
+
if (region.nativeAstNodeId && mapping.nativeAstNodeId === region.nativeAstNodeId) return true;
|
|
3562
|
+
if (symbolIds.has(mapping.semanticSymbolId)) return true;
|
|
3563
|
+
if (occurrenceIds.has(mapping.semanticOccurrenceId)) return true;
|
|
3564
|
+
if (region.granularity === 'file') {
|
|
3565
|
+
return !region.sourcePath || sourceSpanPathMatches(mapping.sourceSpan, region.sourcePath);
|
|
3566
|
+
}
|
|
3567
|
+
return false;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
function sourceSpanPathMatches(span, sourcePath) {
|
|
3571
|
+
if (!span || !sourcePath) return false;
|
|
3572
|
+
return span.path === sourcePath || span.sourceId === sourcePath;
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3575
|
+
function nativeChangeSymbolTouchesRegion(symbol, region) {
|
|
3576
|
+
return Boolean(symbol && region && (
|
|
3577
|
+
(region.id && symbol.ownershipRegionId === region.id) ||
|
|
3578
|
+
(region.key && (
|
|
3579
|
+
symbol.ownershipKey === region.key ||
|
|
3580
|
+
symbol.beforeOwnershipKey === region.key ||
|
|
3581
|
+
symbol.afterOwnershipKey === region.key
|
|
3582
|
+
))
|
|
3583
|
+
));
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
function nativeChangedRegionProjectionAction(region, readiness) {
|
|
3587
|
+
if (readiness === 'blocked') return 'rerun-or-human-port';
|
|
3588
|
+
if (region.changeKind === 'added') return 'review-addition';
|
|
3589
|
+
if (region.changeKind === 'removed') return 'review-removal';
|
|
3590
|
+
if (region.granularity === 'file') return 'review-file';
|
|
3591
|
+
return 'review-port';
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
function nativeImportSourcePreservationRecord(imported) {
|
|
3595
|
+
return imported?.metadata?.sourcePreservation
|
|
3596
|
+
?? imported?.nativeSource?.metadata?.sourcePreservation
|
|
3597
|
+
?? imported?.nativeAst?.metadata?.sourcePreservation
|
|
3598
|
+
?? imported?.universalAst?.metadata?.sourcePreservation;
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
function summarizeNativeChangedRegionProjections(regions) {
|
|
3602
|
+
const projections = (regions ?? [])
|
|
3603
|
+
.map((region) => region?.metadata?.changedRegionProjection)
|
|
3604
|
+
.filter(Boolean);
|
|
3605
|
+
return {
|
|
3606
|
+
schema: 'frontier.lang.changedRegionProjectionSummary.v1',
|
|
3607
|
+
total: regions?.length ?? 0,
|
|
3608
|
+
withProjection: projections.length,
|
|
3609
|
+
reviewRequired: projections.filter((projection) => projection.reviewRequired === true).length,
|
|
3610
|
+
autoMergeClaims: projections.filter((projection) => projection.autoMergeClaim === true).length,
|
|
3611
|
+
sourceMapLinks: projections.reduce((sum, projection) => sum + (projection.sourceMapLinks?.length ?? 0), 0),
|
|
3612
|
+
byAction: countBy(projections.map((projection) => projection.admission?.action ?? 'unknown')),
|
|
3613
|
+
byRegionKind: countBy(projections.map((projection) => projection.region?.kind ?? 'unknown'))
|
|
3614
|
+
};
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3403
3617
|
function nativeImportReadiness(imported) {
|
|
3404
3618
|
return imported?.metadata?.semanticMergeReadiness
|
|
3405
3619
|
?? imported?.metadata?.nativeImportLossSummary?.semanticMergeReadiness
|
|
@@ -3463,11 +3677,31 @@ function nativeChangeSpans(changedSymbols, changedRegions, input) {
|
|
|
3463
3677
|
symbolId: region.symbolId,
|
|
3464
3678
|
span: region.sourceSpan,
|
|
3465
3679
|
conflictKey: region.conflictKey ?? `region:${region.key ?? region.id}`,
|
|
3466
|
-
metadata: {
|
|
3680
|
+
metadata: {
|
|
3681
|
+
changeKind: region.changeKind,
|
|
3682
|
+
regionKind: region.regionKind,
|
|
3683
|
+
granularity: region.granularity,
|
|
3684
|
+
...(region.metadata?.changedRegionProjection ? {
|
|
3685
|
+
changedRegionProjection: nativeChangedRegionProjectionSpanMetadata(region.metadata.changedRegionProjection)
|
|
3686
|
+
} : {})
|
|
3687
|
+
}
|
|
3467
3688
|
}));
|
|
3468
3689
|
return uniqueRecordsById([...symbolSpans, ...regionSpans]);
|
|
3469
3690
|
}
|
|
3470
3691
|
|
|
3692
|
+
function nativeChangedRegionProjectionSpanMetadata(projection) {
|
|
3693
|
+
return {
|
|
3694
|
+
schema: projection.schema,
|
|
3695
|
+
id: projection.id,
|
|
3696
|
+
reviewRequired: projection.reviewRequired,
|
|
3697
|
+
autoMergeClaim: projection.autoMergeClaim,
|
|
3698
|
+
beforeSourceHash: projection.before?.sourceHash,
|
|
3699
|
+
afterSourceHash: projection.after?.sourceHash,
|
|
3700
|
+
sourceMapLinks: projection.sourceMapLinks?.length ?? 0,
|
|
3701
|
+
admission: projection.admission
|
|
3702
|
+
};
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3471
3705
|
function nativeSourceChangeSummary(changedSymbols, changedRegions, sourceChanged) {
|
|
3472
3706
|
return {
|
|
3473
3707
|
sourceChanged,
|
|
@@ -4019,10 +4253,23 @@ function scanJavaScriptLike(input) {
|
|
|
4019
4253
|
const declarations = [];
|
|
4020
4254
|
let currentClass;
|
|
4021
4255
|
let classDepth = 0;
|
|
4256
|
+
let currentObject;
|
|
4257
|
+
const lexicalState = { inBlockComment: false, inTemplateString: false };
|
|
4022
4258
|
for (const { line, number } of sourceLines(input.sourceText)) {
|
|
4023
|
-
const
|
|
4259
|
+
const scanLine = jsDeclarationScanLine(line, lexicalState);
|
|
4260
|
+
const trimmed = scanLine.trim();
|
|
4261
|
+
if (!trimmed || jsCommentOnlyLine(trimmed)) continue;
|
|
4024
4262
|
const declarationLine = trimmed.replace(/^(?:export\s+)?(?:declare\s+)?/, '');
|
|
4025
4263
|
let match;
|
|
4264
|
+
if (currentObject) {
|
|
4265
|
+
const routeRecord = jsRouteRecordDeclaration(input, number, trimmed, currentObject);
|
|
4266
|
+
if (routeRecord) {
|
|
4267
|
+
declarations.push(routeRecord);
|
|
4268
|
+
} else {
|
|
4269
|
+
const property = jsObjectPropertyDeclaration(input, number, trimmed, currentObject);
|
|
4270
|
+
if (property) declarations.push(property);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4026
4273
|
if ((match = trimmed.match(/^import\s+(?:.+?\s+from\s+)?['"]([^'"]+)['"]/))) {
|
|
4027
4274
|
declarations.push(nativeImportDeclaration(input, number, match[1], 'ImportDeclaration', 'module'));
|
|
4028
4275
|
} else if ((match = trimmed.match(/^import\s*\(\s*['"]([^'"]+)['"]\s*\)/))) {
|
|
@@ -4050,11 +4297,20 @@ function scanJavaScriptLike(input) {
|
|
|
4050
4297
|
} else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?\(?([^=;]*)\)?\s*=>/))) {
|
|
4051
4298
|
declarations.push(nativeDeclaration(input, number, 'VariableFunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2]) }, true));
|
|
4052
4299
|
} else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/))) {
|
|
4053
|
-
|
|
4300
|
+
const initializerKind = jsInitializerKind(declarationLine);
|
|
4301
|
+
const regionKind = jsRegionKindForDeclarationName(match[1], declarationLine);
|
|
4302
|
+
declarations.push(nativeDeclaration(input, number, 'VariableDeclaration', jsVariableSymbolKind(regionKind, initializerKind), match[1], {
|
|
4303
|
+
initializerKind
|
|
4304
|
+
}, jsVariableHasBody(initializerKind, declarationLine), {
|
|
4305
|
+
regionKind,
|
|
4306
|
+
metadata: { initializerKind }
|
|
4307
|
+
}));
|
|
4308
|
+
currentObject = jsObjectRegionContext(match[1], declarationLine, number, regionKind);
|
|
4054
4309
|
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=\s*(?:async\s+)?function\*?\s*\(([^)]*)\)/))) {
|
|
4055
4310
|
declarations.push(nativeDeclaration(input, number, 'CommonJsFunctionExport', 'function', match[1], { parameters: splitParameters(match[2]) }, true));
|
|
4056
4311
|
} else if ((match = trimmed.match(/^(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=/))) {
|
|
4057
|
-
|
|
4312
|
+
const regionKind = jsRegionKindForDeclarationName(match[1], trimmed);
|
|
4313
|
+
declarations.push(nativeDeclaration(input, number, 'CommonJsExport', 'variable', match[1], { export: 'commonjs' }, false, { regionKind }));
|
|
4058
4314
|
} else if (currentClass && (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*[^={]+)?(?:\{|=>|$)/)) && !jsControlKeyword(match[1])) {
|
|
4059
4315
|
declarations.push(nativeDeclaration(input, number, 'MethodDefinition', 'method', `${currentClass}.${match[1]}`, {
|
|
4060
4316
|
methodName: match[1],
|
|
@@ -4075,10 +4331,224 @@ function scanJavaScriptLike(input) {
|
|
|
4075
4331
|
classDepth = 0;
|
|
4076
4332
|
}
|
|
4077
4333
|
}
|
|
4334
|
+
if (currentObject) {
|
|
4335
|
+
if (number !== currentObject.startLine) currentObject.depth += jsContainerDelta(trimmed);
|
|
4336
|
+
if (currentObject.depth <= 0) currentObject = undefined;
|
|
4337
|
+
}
|
|
4078
4338
|
}
|
|
4079
4339
|
return declarations;
|
|
4080
4340
|
}
|
|
4081
4341
|
|
|
4342
|
+
function jsCommentOnlyLine(trimmed) {
|
|
4343
|
+
return trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*');
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
function jsDeclarationScanLine(line, state) {
|
|
4347
|
+
let text = String(line ?? '');
|
|
4348
|
+
if (state.inTemplateString) {
|
|
4349
|
+
const close = findUnescapedBacktick(text, 0);
|
|
4350
|
+
if (close < 0) return '';
|
|
4351
|
+
text = text.slice(close + 1);
|
|
4352
|
+
state.inTemplateString = false;
|
|
4353
|
+
}
|
|
4354
|
+
if (state.inBlockComment) {
|
|
4355
|
+
const close = text.indexOf('*/');
|
|
4356
|
+
if (close < 0) return '';
|
|
4357
|
+
text = text.slice(close + 2);
|
|
4358
|
+
state.inBlockComment = false;
|
|
4359
|
+
}
|
|
4360
|
+
let output = '';
|
|
4361
|
+
let quote;
|
|
4362
|
+
let escaped = false;
|
|
4363
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
4364
|
+
const char = text[index];
|
|
4365
|
+
const next = text[index + 1];
|
|
4366
|
+
if (quote) {
|
|
4367
|
+
output += char;
|
|
4368
|
+
if (escaped) {
|
|
4369
|
+
escaped = false;
|
|
4370
|
+
} else if (char === '\\') {
|
|
4371
|
+
escaped = true;
|
|
4372
|
+
} else if (char === quote) {
|
|
4373
|
+
quote = undefined;
|
|
4374
|
+
}
|
|
4375
|
+
continue;
|
|
4376
|
+
}
|
|
4377
|
+
if (char === '/' && next === '/') break;
|
|
4378
|
+
if (char === '/' && next === '*') {
|
|
4379
|
+
const close = text.indexOf('*/', index + 2);
|
|
4380
|
+
if (close < 0) {
|
|
4381
|
+
state.inBlockComment = true;
|
|
4382
|
+
break;
|
|
4383
|
+
}
|
|
4384
|
+
index = close + 1;
|
|
4385
|
+
continue;
|
|
4386
|
+
}
|
|
4387
|
+
if (char === '\'' || char === '"') {
|
|
4388
|
+
quote = char;
|
|
4389
|
+
output += char;
|
|
4390
|
+
continue;
|
|
4391
|
+
}
|
|
4392
|
+
if (char === '`') {
|
|
4393
|
+
const close = findUnescapedBacktick(text, index + 1);
|
|
4394
|
+
if (close < 0) {
|
|
4395
|
+
state.inTemplateString = true;
|
|
4396
|
+
output += '``';
|
|
4397
|
+
break;
|
|
4398
|
+
}
|
|
4399
|
+
output += text.slice(index, close + 1);
|
|
4400
|
+
index = close;
|
|
4401
|
+
continue;
|
|
4402
|
+
}
|
|
4403
|
+
output += char;
|
|
4404
|
+
}
|
|
4405
|
+
return output;
|
|
4406
|
+
}
|
|
4407
|
+
|
|
4408
|
+
function findUnescapedBacktick(text, startIndex) {
|
|
4409
|
+
let escaped = false;
|
|
4410
|
+
for (let index = startIndex; index < text.length; index += 1) {
|
|
4411
|
+
const char = text[index];
|
|
4412
|
+
if (escaped) {
|
|
4413
|
+
escaped = false;
|
|
4414
|
+
} else if (char === '\\') {
|
|
4415
|
+
escaped = true;
|
|
4416
|
+
} else if (char === '`') {
|
|
4417
|
+
return index;
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
return -1;
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
function jsObjectRegionContext(name, declarationLine, lineNumber, regionKind) {
|
|
4424
|
+
const initializerKind = jsInitializerKind(declarationLine);
|
|
4425
|
+
if (initializerKind !== 'object' && initializerKind !== 'array') return undefined;
|
|
4426
|
+
const depth = jsContainerDelta(declarationLine);
|
|
4427
|
+
if (depth <= 0) return undefined;
|
|
4428
|
+
return {
|
|
4429
|
+
name,
|
|
4430
|
+
regionKind: regionKind ?? jsRegionKindForDeclarationName(name, declarationLine),
|
|
4431
|
+
initializerKind,
|
|
4432
|
+
depth,
|
|
4433
|
+
startLine: lineNumber
|
|
4434
|
+
};
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
function jsInitializerKind(line) {
|
|
4438
|
+
const initializer = String(line ?? '').split('=').slice(1).join('=').trim();
|
|
4439
|
+
if (!initializer) return 'unknown';
|
|
4440
|
+
if (/^(?:async\s+)?function\b/.test(initializer) || /=>/.test(initializer)) return 'function';
|
|
4441
|
+
if (initializer.startsWith('{')) return 'object';
|
|
4442
|
+
if (initializer.startsWith('[')) return 'array';
|
|
4443
|
+
if (/^new\s+/.test(initializer)) return 'instance';
|
|
4444
|
+
if (/^['"`]/.test(initializer)) return 'string';
|
|
4445
|
+
if (/^(?:true|false)\b/.test(initializer)) return 'boolean';
|
|
4446
|
+
if (/^[0-9]/.test(initializer)) return 'number';
|
|
4447
|
+
return 'expression';
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
function jsVariableHasBody(initializerKind, declarationLine) {
|
|
4451
|
+
return initializerKind === 'function'
|
|
4452
|
+
|| initializerKind === 'object'
|
|
4453
|
+
|| initializerKind === 'array'
|
|
4454
|
+
|| /\{/.test(String(declarationLine ?? ''));
|
|
4455
|
+
}
|
|
4456
|
+
|
|
4457
|
+
function jsVariableSymbolKind(regionKind, initializerKind) {
|
|
4458
|
+
if (regionKind === 'route') return 'route';
|
|
4459
|
+
if (initializerKind === 'function') return 'function';
|
|
4460
|
+
return 'variable';
|
|
4461
|
+
}
|
|
4462
|
+
|
|
4463
|
+
function jsRegionKindForDeclarationName(name, source = '') {
|
|
4464
|
+
const raw = `${name ?? ''} ${source ?? ''}`;
|
|
4465
|
+
const text = raw.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase();
|
|
4466
|
+
const compact = raw.toLowerCase();
|
|
4467
|
+
if (/\b(routes?|router|screens?|pages?|navigation|navitems?|menuitems?)\b/.test(text) || /(route|router|screen|page|navigation|navitem|menuitem)/.test(compact)) return 'route';
|
|
4468
|
+
if (/\b(config|settings|options|flags?|schema|manifest|registry|catalog)\b/.test(text) || /(config|settings|options|flags|schema|manifest|registry|catalog)/.test(compact)) return 'config';
|
|
4469
|
+
if (/\b(content|copy|docs?|legal|messages?|strings?|i18n|locale|translations?)\b/.test(text) || /(content|copy|docs|legal|messages|strings|i18n|locale|translations)/.test(compact)) return 'content';
|
|
4470
|
+
return undefined;
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4473
|
+
function jsObjectPropertyDeclaration(input, lineNumber, trimmed, context) {
|
|
4474
|
+
if (/^[}\])]/.test(trimmed) || trimmed.startsWith('...')) return undefined;
|
|
4475
|
+
const methodMatch = trimmed.match(/^(?:(?:async|get|set)\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|,|$)/);
|
|
4476
|
+
if (methodMatch && !jsControlKeyword(methodMatch[2])) {
|
|
4477
|
+
const name = `${context.name}.${methodMatch[2]}`;
|
|
4478
|
+
return nativeDeclaration(input, lineNumber, 'ObjectMethod', 'function', name, {
|
|
4479
|
+
owner: context.name,
|
|
4480
|
+
propertyName: methodMatch[2],
|
|
4481
|
+
parameters: splitParameters(methodMatch[3])
|
|
4482
|
+
}, true, {
|
|
4483
|
+
regionKind: jsPropertyRegionKind(context, methodMatch[2], 'function'),
|
|
4484
|
+
metadata: { owner: context.name, propertyName: methodMatch[2], initializerKind: 'function' }
|
|
4485
|
+
});
|
|
4486
|
+
}
|
|
4487
|
+
const propertyMatch = trimmed.match(/^(?:(['"])([^'"]+)\1|([A-Za-z_$][\w$-]*))\s*:\s*(.+?)(?:,)?$/);
|
|
4488
|
+
if (!propertyMatch) return undefined;
|
|
4489
|
+
const propertyName = propertyMatch[2] ?? propertyMatch[3];
|
|
4490
|
+
if (!propertyName || jsControlKeyword(propertyName)) return undefined;
|
|
4491
|
+
const value = propertyMatch[4].trim();
|
|
4492
|
+
const initializerKind = jsPropertyInitializerKind(value);
|
|
4493
|
+
const functionLike = initializerKind === 'function';
|
|
4494
|
+
const name = `${context.name}.${propertyName}`;
|
|
4495
|
+
return nativeDeclaration(input, lineNumber, functionLike ? 'ObjectFunctionProperty' : 'ObjectProperty', functionLike ? 'function' : 'property', name, {
|
|
4496
|
+
owner: context.name,
|
|
4497
|
+
propertyName,
|
|
4498
|
+
initializerKind
|
|
4499
|
+
}, functionLike || initializerKind === 'object' || initializerKind === 'array', {
|
|
4500
|
+
regionKind: jsPropertyRegionKind(context, propertyName, value),
|
|
4501
|
+
metadata: {
|
|
4502
|
+
owner: context.name,
|
|
4503
|
+
propertyName,
|
|
4504
|
+
initializerKind
|
|
4505
|
+
}
|
|
4506
|
+
});
|
|
4507
|
+
}
|
|
4508
|
+
|
|
4509
|
+
function jsRouteRecordDeclaration(input, lineNumber, trimmed, context) {
|
|
4510
|
+
if (context.regionKind !== 'route') return undefined;
|
|
4511
|
+
const match = trimmed.match(/\b(?:path|route|href|url)\s*:\s*(['"`])([^'"`]+)\1/);
|
|
4512
|
+
if (!match) return undefined;
|
|
4513
|
+
const routePath = match[2];
|
|
4514
|
+
return nativeDeclaration(input, lineNumber, 'RouteRecord', 'route', `${context.name}.${routePath}`, {
|
|
4515
|
+
owner: context.name,
|
|
4516
|
+
routePath
|
|
4517
|
+
}, true, {
|
|
4518
|
+
regionKind: 'route',
|
|
4519
|
+
metadata: { owner: context.name, routePath, initializerKind: 'object' }
|
|
4520
|
+
});
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4523
|
+
function jsPropertyInitializerKind(value) {
|
|
4524
|
+
const text = String(value ?? '').trim();
|
|
4525
|
+
if (/^(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(text)) return 'function';
|
|
4526
|
+
if (text.startsWith('{')) return 'object';
|
|
4527
|
+
if (text.startsWith('[')) return 'array';
|
|
4528
|
+
if (/^['"`]/.test(text)) return 'string';
|
|
4529
|
+
if (/^(?:true|false)\b/.test(text)) return 'boolean';
|
|
4530
|
+
if (/^[0-9]/.test(text)) return 'number';
|
|
4531
|
+
return 'expression';
|
|
4532
|
+
}
|
|
4533
|
+
|
|
4534
|
+
function jsPropertyRegionKind(context, propertyName, value) {
|
|
4535
|
+
const named = jsRegionKindForDeclarationName(propertyName, value);
|
|
4536
|
+
if (named) return named;
|
|
4537
|
+
if (context.regionKind === 'route') return 'route';
|
|
4538
|
+
if (context.regionKind === 'content') return 'content';
|
|
4539
|
+
if (context.regionKind === 'config') return 'config';
|
|
4540
|
+
return 'property';
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
function jsContainerDelta(source) {
|
|
4544
|
+
let delta = 0;
|
|
4545
|
+
for (const char of String(source ?? '')) {
|
|
4546
|
+
if (char === '{' || char === '[') delta += 1;
|
|
4547
|
+
if (char === '}' || char === ']') delta -= 1;
|
|
4548
|
+
}
|
|
4549
|
+
return delta;
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4082
4552
|
function scanPython(input) {
|
|
4083
4553
|
const declarations = [];
|
|
4084
4554
|
for (const { line, number } of sourceLines(input.sourceText)) {
|
|
@@ -4778,7 +5248,7 @@ function rMetaName(source) {
|
|
|
4778
5248
|
return match?.[1] ?? 'dynamic';
|
|
4779
5249
|
}
|
|
4780
5250
|
|
|
4781
|
-
function nativeDeclaration(input, lineNumber, languageKind, symbolKind, name, fields = {}, hasBody = false) {
|
|
5251
|
+
function nativeDeclaration(input, lineNumber, languageKind, symbolKind, name, fields = {}, hasBody = false, options = {}) {
|
|
4782
5252
|
const nodeId = `native_${idFragment(languageKind)}_${lineNumber}_${idFragment(name)}`;
|
|
4783
5253
|
return {
|
|
4784
5254
|
nodeId,
|
|
@@ -4789,7 +5259,9 @@ function nativeDeclaration(input, lineNumber, languageKind, symbolKind, name, fi
|
|
|
4789
5259
|
symbolId: `symbol:${input.language}:${idFragment(name)}`,
|
|
4790
5260
|
span: spanForLine(input, lineNumber),
|
|
4791
5261
|
fields,
|
|
4792
|
-
metadata: { scan: 'lightweight-declaration', hasBody },
|
|
5262
|
+
metadata: { scan: 'lightweight-declaration', hasBody, ...options.metadata },
|
|
5263
|
+
...(options.regionKind ? { regionKind: options.regionKind } : {}),
|
|
5264
|
+
...(options.role ? { role: options.role } : {}),
|
|
4793
5265
|
...(hasBody ? { loss: opaqueBodyLoss(input, lineNumber, nodeId, name) } : {})
|
|
4794
5266
|
};
|
|
4795
5267
|
}
|
|
@@ -6649,6 +7121,8 @@ function semanticPatchHintForRegion(region, readiness, options = {}) {
|
|
|
6649
7121
|
|
|
6650
7122
|
function semanticRegionKindForDeclaration(declaration) {
|
|
6651
7123
|
if (declaration.role === 'import' || declaration.importPath) return 'import';
|
|
7124
|
+
if (declaration.regionKind) return normalizeNativeImportRegionKind(declaration.regionKind);
|
|
7125
|
+
if (declaration.metadata?.ownershipRegionKind) return normalizeNativeImportRegionKind(declaration.metadata.ownershipRegionKind);
|
|
6652
7126
|
const kind = declaration.symbolKind ?? declaration.kind ?? declaration.nativeNode?.kind;
|
|
6653
7127
|
if (semanticKindIsType(kind)) return 'type';
|
|
6654
7128
|
if (semanticKindCanOwnBody(kind, declaration.span ?? declaration.nativeNode?.span)) return 'body';
|
package/package.json
CHANGED