@shapeshift-labs/frontier-lang-compiler 0.2.68 → 0.2.70

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.
@@ -3,12 +3,21 @@ import type { NativeImportRegionTaxonomyKind } from './native-import-losses.js';
3
3
 
4
4
  export type SemanticImportImpactRisk = 'low' | 'medium' | 'high' | string;
5
5
  export type SemanticImportImpactConfidence = 'source-exact' | 'source-addressed' | 'estimated-source-region' | 'review-required' | string;
6
+ export type SemanticImportMergeSignalStatus = 'strong' | 'partial' | 'weak' | 'blocked' | string;
6
7
 
7
8
  export interface SemanticImportImpactVerificationStep {
8
9
  readonly kind: 'dependency-review' | 'source-map-review' | 'reject-or-reprove' | 'proof-review' | 'patch-admission' | 'evidence-review' | string;
9
10
  readonly reason: string;
10
11
  readonly required: boolean;
11
12
  }
13
+ export interface SemanticImportMergeSignal {
14
+ readonly status: SemanticImportMergeSignalStatus;
15
+ readonly score: number;
16
+ readonly missing: readonly string[];
17
+ readonly reviewRequired: boolean;
18
+ readonly queryKeys: readonly string[];
19
+ }
20
+ export interface SemanticImportMergeSignalScoreSummary { readonly min: number; readonly max: number; readonly average: number; }
12
21
 
13
22
  export interface SemanticImportImpactRecord {
14
23
  readonly id: string;
@@ -39,6 +48,7 @@ export interface SemanticImportImpactRecord {
39
48
  readonly readiness: SemanticMergeReadiness;
40
49
  readonly risk: SemanticImportImpactRisk;
41
50
  readonly confidence: SemanticImportImpactConfidence;
51
+ readonly mergeSignal: SemanticImportMergeSignal;
42
52
  }
43
53
 
44
54
  export interface SemanticImportImpactSummary {
@@ -51,5 +61,7 @@ export interface SemanticImportImpactSummary {
51
61
  readonly sourceMapMappings: number; readonly sourcePreservationRecords: number; readonly patchHints: number;
52
62
  readonly proofObligations: number; readonly openProofObligations: number; readonly failedProofObligations: number; readonly paradigmSemantics: number; readonly loweringRecords: number;
53
63
  readonly evidenceIds: number; readonly verificationPlans: readonly string[]; readonly requiredVerificationSteps: number;
64
+ readonly byMergeSignal: Readonly<Record<string, number>>; readonly weakMergeSignals: number; readonly reviewRequiredMergeSignals: number;
65
+ readonly mergeSignalQueryKeys: readonly string[]; readonly mergeSignalScores: SemanticImportMergeSignalScoreSummary;
54
66
  };
55
67
  }
@@ -1,5 +1,5 @@
1
1
  import{nativeLanguageCompileTarget}from'../../coverage-matrix-profiles.js';import{idFragment,uniqueByEvidenceId,uniqueByLossId}from'../../native-import-utils.js';
2
- import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{createProjectionTargetLossMatrix}from'./createProjectionTargetLossMatrix.js';import{importNativeSource}from'./importNativeSource.js';import{isNativeSourceImportResult}from'./isNativeSourceImportResult.js';import{nativeCompileSourceLanguage}from'./nativeCompileSourceLanguage.js';import{nativeCompileTarget}from'./nativeCompileTarget.js';import{nativeSourceCompileEvidence}from'./nativeSourceCompileEvidence.js';import{nativeSourceCompileSourceMaps}from'./nativeSourceCompileSourceMaps.js';import{nativeSourceCompileTargetCoverage}from'./nativeSourceCompileTargetCoverage.js';import{nativeSourceCompileTargetLosses}from'./nativeSourceCompileTargetLosses.js';import{projectNativeImportToSource}from'./projectNativeImportToSource.js';import{resolveNativeTargetProjectionAdapter}from'./resolveNativeTargetProjectionAdapter.js';import{runNativeTargetProjectionAdapter}from'./runNativeTargetProjectionAdapter.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
2
+ import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{createProjectionTargetLossMatrix}from'./createProjectionTargetLossMatrix.js';import{importNativeSource}from'./importNativeSource.js';import{isNativeSourceImportResult}from'./isNativeSourceImportResult.js';import{nativeCompileSourceLanguage}from'./nativeCompileSourceLanguage.js';import{nativeCompileTarget}from'./nativeCompileTarget.js';import{nativeProjectionReview}from'./nativeProjectionReview.js';import{nativeSourceCompileEvidence}from'./nativeSourceCompileEvidence.js';import{nativeSourceCompileSourceMaps}from'./nativeSourceCompileSourceMaps.js';import{nativeSourceCompileTargetCoverage}from'./nativeSourceCompileTargetCoverage.js';import{nativeSourceCompileTargetLosses}from'./nativeSourceCompileTargetLosses.js';import{projectNativeImportToSource}from'./projectNativeImportToSource.js';import{resolveNativeTargetProjectionAdapter}from'./resolveNativeTargetProjectionAdapter.js';import{runNativeTargetProjectionAdapter}from'./runNativeTargetProjectionAdapter.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
3
3
  export function compileNativeSource(input, options = {}) {
4
4
  const importResult = isNativeSourceImportResult(input) ? input : importNativeSource(input);
5
5
  const sourceLanguage = nativeCompileSourceLanguage(importResult, input);
@@ -124,6 +124,17 @@ export function compileNativeSource(input, options = {}) {
124
124
  compileResultId: id
125
125
  });
126
126
  const sourceMap = sourceMaps[0];
127
+ const projectionReview = nativeProjectionReview({
128
+ mode: projection.mode, outputMode, language: projection.language, sourceLanguage, target,
129
+ sourcePath: importResult.sourcePath ?? importResult.nativeSource?.sourcePath,
130
+ exactSourceAvailable: projection.metadata?.exactSourceAvailable === true,
131
+ sourceTextAvailable: projection.metadata?.sourceTextAvailable === true,
132
+ sourceHashVerified: projection.metadata?.sourceHashVerified === true,
133
+ declarationCount: projection.declarations.length, sourceMapCount: sourceMaps.length,
134
+ losses, targetLosses, readiness: readiness.readiness, targetCoverage, targetProjection
135
+ });
136
+ compileEvidence.metadata.projectionReview = projectionReview;
137
+ for (const record of sourceMaps) record.metadata = { ...(record.metadata ?? {}), projectionReview };
127
138
  const roundtripEvidence = createNativeRoundtripEvidence(importResult, {
128
139
  id: `evidence_${idPart}_${idFragment(target)}_native_roundtrip`,
129
140
  projection,
@@ -179,6 +190,7 @@ export function compileNativeSource(input, options = {}) {
179
190
  targetLossClass: targetCoverage.lossClass,
180
191
  targetReadiness: targetCoverage.readiness,
181
192
  targetSupported: targetCoverage.supported,
193
+ projectionReview,
182
194
  ...options.metadata,
183
195
  roundtripEvidence: roundtripEvidence.metadata.roundtripEvidence
184
196
  }
@@ -9,6 +9,10 @@ export function createUniversalAstFromDocument(document, input = {}) {
9
9
  losses: input.losses,
10
10
  evidence: input.evidence ?? [],
11
11
  mergeCandidates: input.mergeCandidates,
12
+ semanticOperations: input.semanticOperations,
13
+ proof: input.proof ?? input.universalAstProof,
14
+ paradigmSemantics: input.paradigmSemantics ?? input.universalAstParadigmSemantics,
15
+ replayLinks: input.replayLinks,
12
16
  layers: input.layers,
13
17
  metadata: input.metadata
14
18
  }), input);
@@ -0,0 +1,73 @@
1
+ import{uniqueStrings}from'../../native-import-utils.js';
2
+
3
+ export function nativeProjectionReview(input) {
4
+ const lossIds = (input.losses ?? []).map((loss) => loss.id).filter(Boolean);
5
+ const blockingLossIds = (input.losses ?? []).filter((loss) => loss.severity === 'error').map((loss) => loss.id).filter(Boolean);
6
+ const targetLossIds = (input.targetLosses ?? []).map((loss) => loss.id).filter(Boolean);
7
+ const fallbackReasons = nativeProjectionFallbackReasons(input, blockingLossIds, targetLossIds);
8
+ const reviewRequired = input.readiness !== 'ready' || fallbackReasons.length > 0 || blockingLossIds.length > 0;
9
+ const status = nativeProjectionReviewStatus(input, blockingLossIds);
10
+ return {
11
+ kind: 'frontier.lang.nativeProjectionReview',
12
+ version: 1,
13
+ status,
14
+ reviewRequired,
15
+ projectionMode: input.mode,
16
+ outputMode: input.outputMode ?? input.mode,
17
+ language: input.language,
18
+ sourceLanguage: input.sourceLanguage ?? input.language,
19
+ target: input.target,
20
+ sourcePath: input.sourcePath,
21
+ exactSourceAvailable: input.exactSourceAvailable === true,
22
+ sourceTextAvailable: input.sourceTextAvailable === true,
23
+ sourceHashVerified: input.sourceHashVerified === true,
24
+ declarationCount: input.declarationCount ?? 0,
25
+ sourceMapCount: input.sourceMapCount ?? 0,
26
+ readiness: input.readiness,
27
+ targetLossClass: input.targetCoverage?.lossClass,
28
+ targetReadiness: input.targetCoverage?.readiness,
29
+ targetSupported: input.targetCoverage?.supported,
30
+ targetProjectionAdapterId: input.targetProjection?.adapter?.id,
31
+ fallbackReasons,
32
+ lossIds: uniqueStrings(lossIds),
33
+ blockingLossIds: uniqueStrings(blockingLossIds),
34
+ targetLossIds: uniqueStrings(targetLossIds),
35
+ queryKeys: nativeProjectionReviewQueryKeys(input, status, fallbackReasons, reviewRequired)
36
+ };
37
+ }
38
+
39
+ function nativeProjectionFallbackReasons(input, blockingLossIds, targetLossIds) {
40
+ const reasons = [];
41
+ if (input.exactSourceAvailable !== true) reasons.push('no-exact-source');
42
+ if (input.sourceHashVerified !== true) reasons.push('source-hash-unverified');
43
+ if (input.mode === 'native-source-stubs') reasons.push('declaration-stubs');
44
+ if (input.outputMode === 'target-stubs') reasons.push('target-stubs');
45
+ if (input.targetCoverage?.supported === false) reasons.push('target-unsupported');
46
+ if (input.targetCoverage?.lossClass === 'missingAdapter') reasons.push('missing-target-adapter');
47
+ if (blockingLossIds.length > 0) reasons.push('blocking-losses');
48
+ if (targetLossIds.length > 0) reasons.push('target-losses');
49
+ return uniqueStrings(reasons);
50
+ }
51
+
52
+ function nativeProjectionReviewStatus(input, blockingLossIds) {
53
+ if (blockingLossIds.length > 0 || input.readiness === 'blocked' || input.targetCoverage?.readiness === 'blocked') return 'blocked';
54
+ if (input.outputMode === 'target-adapter') return 'target-adapter';
55
+ if (input.outputMode === 'target-stubs' || input.mode === 'native-source-stubs') return 'stub-only';
56
+ if (input.sourceHashVerified === true && input.exactSourceAvailable === true) return 'preserved-source';
57
+ return 'needs-review';
58
+ }
59
+
60
+ function nativeProjectionReviewQueryKeys(input, status, fallbackReasons, reviewRequired) {
61
+ return uniqueStrings([
62
+ `projection-review:${status}`,
63
+ reviewRequired ? 'review-required' : 'review-not-required',
64
+ input.language ? `language:${input.language}` : undefined,
65
+ input.sourceLanguage ? `source-language:${input.sourceLanguage}` : undefined,
66
+ input.target ? `target:${input.target}` : undefined,
67
+ input.sourcePath ? `source:${input.sourcePath}` : undefined,
68
+ input.mode ? `projection-mode:${input.mode}` : undefined,
69
+ input.outputMode ? `output-mode:${input.outputMode}` : undefined,
70
+ input.targetCoverage?.lossClass ? `target-loss-class:${input.targetCoverage.lossClass}` : undefined,
71
+ ...fallbackReasons.map((reason) => `fallback:${reason}`)
72
+ ].filter(Boolean));
73
+ }
@@ -1,5 +1,5 @@
1
1
  import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
2
- import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{nativeImportProjectionContext}from'./nativeImportProjectionContext.js';import{nativeProjectionDeclarations}from'./nativeProjectionDeclarations.js';import{nativeProjectionSourceCandidate}from'./nativeProjectionSourceCandidate.js';import{nativeProjectionStubLosses}from'./nativeProjectionStubLosses.js';import{renderNativeProjectionStubs}from'./renderNativeProjectionStubs.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
2
+ import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{nativeImportProjectionContext}from'./nativeImportProjectionContext.js';import{nativeProjectionDeclarations}from'./nativeProjectionDeclarations.js';import{nativeProjectionReview}from'./nativeProjectionReview.js';import{nativeProjectionSourceCandidate}from'./nativeProjectionSourceCandidate.js';import{nativeProjectionStubLosses}from'./nativeProjectionStubLosses.js';import{renderNativeProjectionStubs}from'./renderNativeProjectionStubs.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
3
3
  export function projectNativeImportToSource(importResult, options = {}) {
4
4
  if (!importResult || typeof importResult !== 'object') {
5
5
  throw new Error('projectNativeImportToSource requires a native import result');
@@ -49,6 +49,14 @@ export function projectNativeImportToSource(importResult, options = {}) {
49
49
  parser: context.parser,
50
50
  semanticStatus: context.semanticStatus
51
51
  });
52
+ const projectionReview = nativeProjectionReview({
53
+ mode, language: context.language, sourcePath: context.sourcePath,
54
+ exactSourceAvailable: candidateSource?.exact === true,
55
+ sourceTextAvailable: typeof candidateSource?.sourceText === 'string',
56
+ sourceHashVerified: candidateSource?.hashVerified ?? false,
57
+ declarationCount: declarations.length, losses, readiness: readiness.readiness
58
+ });
59
+ evidence[0].metadata.projectionReview = projectionReview;
52
60
  const result = {
53
61
  kind: 'frontier.lang.nativeSourceProjection',
54
62
  version: 1,
@@ -75,6 +83,7 @@ export function projectNativeImportToSource(importResult, options = {}) {
75
83
  sourcePreservationId: candidateSource?.sourcePreservationId,
76
84
  sourceHashVerified: candidateSource?.hashVerified ?? false,
77
85
  nativeImportLossSummary,
86
+ projectionReview,
78
87
  ...options.metadata
79
88
  }
80
89
  };
@@ -30,6 +30,14 @@ export function jsImportDeclarations(input, lineNumber, trimmed) {
30
30
  : [];
31
31
  return jsImportModuleDeclarations(input, lineNumber, importPath, 'ExportFromDeclaration', bindings, { typeOnly, reexport: true, exportStar: Boolean(exportMatch[2]) });
32
32
  }
33
+ const destructuredRequireMatch = trimmed.match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=\s*(?:await\s+)?(require|import)\s*\(\s*(['"])([^'"]+)\3\s*\)/);
34
+ if (destructuredRequireMatch) {
35
+ const importKind = destructuredRequireMatch[2] === 'import' ? 'dynamic-import-binding' : 'commonjs-require';
36
+ const bindings = jsDestructuredImportBindings(destructuredRequireMatch[1], importKind);
37
+ if (bindings.length) {
38
+ return jsImportModuleDeclarations(input, lineNumber, destructuredRequireMatch[4], 'DestructuredRequireDeclaration', bindings, { destructured: true });
39
+ }
40
+ }
33
41
  const requireMatch = trimmed.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:await\s+)?(?:require|import)\s*\(\s*(['"])([^'"]+)\2\s*\)/);
34
42
  if (requireMatch) return jsImportModuleDeclarations(input, lineNumber, requireMatch[3], 'CommonJsRequireDeclaration', [{
35
43
  localName: requireMatch[1],
@@ -39,6 +47,23 @@ export function jsImportDeclarations(input, lineNumber, trimmed) {
39
47
  return [];
40
48
  }
41
49
 
50
+ function jsDestructuredImportBindings(raw, importKind) {
51
+ return String(raw ?? '')
52
+ .split(',')
53
+ .map((part) => {
54
+ const text = part.trim();
55
+ if (!text || text.startsWith('...')) return undefined;
56
+ const match = text.match(/^([A-Za-z_$][\w$]*|\*)\s*(?::\s*([A-Za-z_$][\w$]*))?$/);
57
+ if (!match) return undefined;
58
+ return {
59
+ localName: match[2] ?? match[1],
60
+ importedName: match[1],
61
+ importKind
62
+ };
63
+ })
64
+ .filter(Boolean);
65
+ }
66
+
42
67
  function jsImportModuleDeclarations(input, lineNumber, importPath, languageKind, bindings = [], metadata = {}) {
43
68
  const bindingSummaries = bindings.map((binding) => ({
44
69
  localName: binding.localName,
@@ -55,7 +80,8 @@ function jsImportModuleDeclarations(input, lineNumber, importPath, languageKind,
55
80
  ...(metadata.typeOnly ? { typeOnly: true } : {}),
56
81
  ...(metadata.sideEffectOnly ? { sideEffectOnly: true } : {}),
57
82
  ...(metadata.reexport ? { reexport: true } : {}),
58
- ...(metadata.exportStar ? { exportStar: true } : {})
83
+ ...(metadata.exportStar ? { exportStar: true } : {}),
84
+ ...(metadata.destructured ? { destructured: true } : {})
59
85
  },
60
86
  metadata: {
61
87
  moduleOnly: true,
@@ -33,6 +33,7 @@ function scanJavaScriptLike(input) {
33
33
  let currentClass;
34
34
  let classDepth = 0;
35
35
  let currentObject;
36
+ let currentType;
36
37
  const lexicalState = { inBlockComment: false, inTemplateString: false };
37
38
  for (const { line, number } of lines) {
38
39
  const scanLine = jsDeclarationScanLine(line, lexicalState);
@@ -40,6 +41,9 @@ function scanJavaScriptLike(input) {
40
41
  if (!trimmed || jsCommentOnlyLine(trimmed)) continue;
41
42
  const declarationLine = trimmed.replace(/^(?:export\s+)?(?:declare\s+)?/, '');
42
43
  let match;
44
+ if (currentType && number !== currentType.startLine) {
45
+ pushDeclaration(jsTypeMemberDeclaration(input, number, declarationLine, currentType));
46
+ }
43
47
  if (currentObject) {
44
48
  const routeRecord = jsRouteRecordDeclaration(input, number, trimmed, currentObject);
45
49
  if (routeRecord) {
@@ -66,13 +70,18 @@ function scanJavaScriptLike(input) {
66
70
  classDepth = 0;
67
71
  }
68
72
  } else if ((match = declarationLine.match(/^interface\s+([A-Za-z_$][\w$]*)/))) {
69
- pushDeclaration(nativeDeclaration(input, number, 'InterfaceDeclaration', 'interface', match[1], {}, declarationLine.includes('{')));
73
+ const regionKind = 'type';
74
+ pushDeclaration(nativeDeclaration(input, number, 'InterfaceDeclaration', 'interface', match[1], {}, declarationLine.includes('{'), { regionKind }));
75
+ currentType = jsTypeRegionContext(match[1], declarationLine, number, regionKind, 'interface');
70
76
  } else if ((match = declarationLine.match(/^(?:const\s+)?enum\s+([A-Za-z_$][\w$]*)/))) {
71
77
  pushDeclaration(nativeDeclaration(input, number, 'EnumDeclaration', 'type', match[1], {}, declarationLine.includes('{')));
72
78
  } else if ((match = declarationLine.match(/^(?:namespace|module)\s+([A-Za-z_$][\w$.]*)/))) {
73
79
  pushDeclaration(nativeDeclaration(input, number, 'ModuleDeclaration', 'module', match[1], {}, declarationLine.includes('{')));
74
- } else if ((match = declarationLine.match(/^type\s+([A-Za-z_$][\w$]*)\s*=/))) {
75
- pushDeclaration(nativeDeclaration(input, number, 'TypeAliasDeclaration', 'type', match[1], {}, false));
80
+ } else if ((match = declarationLine.match(/^type\s+([A-Za-z_$][\w$]*)(?:\s*<[^=]+>)?\s*=/))) {
81
+ const regionKind = 'type';
82
+ const hasTypeBody = declarationLine.includes('{');
83
+ pushDeclaration(nativeDeclaration(input, number, 'TypeAliasDeclaration', 'type', match[1], {}, hasTypeBody, { regionKind }));
84
+ currentType = jsTypeRegionContext(match[1], declarationLine, number, regionKind, 'type');
76
85
  } else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::\s*[^=]+)?=\s*(?:async\s*)?(?:<[^=]+>\s*)?(?:\(([^)]*)\)|([A-Za-z_$][\w$]*))\s*(?::\s*[^=]+)?=>/))) {
77
86
  pushDeclaration(nativeDeclaration(input, number, 'VariableFunctionDeclaration', 'function', match[1], { parameters: splitParameters(match[2] ?? match[3]) }, true));
78
87
  } else if ((match = declarationLine.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/))) {
@@ -113,6 +122,10 @@ function scanJavaScriptLike(input) {
113
122
  classDepth = 0;
114
123
  }
115
124
  }
125
+ if (currentType) {
126
+ if (number !== currentType.startLine) currentType.depth += jsStructureDelta(trimmed).value;
127
+ if (currentType.depth <= 0) currentType = undefined;
128
+ }
116
129
  if (currentObject) {
117
130
  if (number !== currentObject.startLine) currentObject.depth += jsContainerDelta(trimmed);
118
131
  if (currentObject.depth <= 0) currentObject = undefined;
@@ -179,6 +192,53 @@ function jsStructureDelta(source) {
179
192
  return { value, opened };
180
193
  }
181
194
 
195
+ function jsTypeRegionContext(name, declarationLine, lineNumber, regionKind, typeKind) {
196
+ const depth = jsStructureDelta(declarationLine).value;
197
+ if (depth <= 0) return undefined;
198
+ return {
199
+ name,
200
+ typeKind,
201
+ regionKind,
202
+ depth,
203
+ startLine: lineNumber
204
+ };
205
+ }
206
+
207
+ function jsTypeMemberDeclaration(input, lineNumber, declarationLine, context) {
208
+ const text = String(declarationLine ?? '').trim();
209
+ if (!text || /^[}\])]/.test(text) || text.startsWith('//')) return undefined;
210
+ let match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*([^;,]+))?[;,]?$/);
211
+ if (match && !jsControlKeyword(match[2])) {
212
+ return nativeDeclaration(input, lineNumber, 'TypeMethodSignature', 'method', `${context.name}.${match[2]}`, {
213
+ owner: context.name,
214
+ propertyName: match[2],
215
+ parameters: splitParameters(match[3]),
216
+ returnType: match[4]?.trim(),
217
+ typeKind: context.typeKind
218
+ }, false, {
219
+ regionKind: jsTypeMemberRegionKind(context, match[2], text),
220
+ metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
221
+ });
222
+ }
223
+ match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*:\s*(.+?)[;,]?$/);
224
+ if (!match || jsControlKeyword(match[2])) return undefined;
225
+ const valueType = match[3].trim();
226
+ const functionLike = /=>/.test(valueType) || /^\([^)]*\)\s*=>/.test(valueType);
227
+ return nativeDeclaration(input, lineNumber, functionLike ? 'TypeFunctionPropertySignature' : 'TypePropertySignature', functionLike ? 'function' : 'property', `${context.name}.${match[2]}`, {
228
+ owner: context.name,
229
+ propertyName: match[2],
230
+ valueType,
231
+ typeKind: context.typeKind
232
+ }, false, {
233
+ regionKind: jsTypeMemberRegionKind(context, match[2], text),
234
+ metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
235
+ });
236
+ }
237
+
238
+ function jsTypeMemberRegionKind(context, propertyName, source) {
239
+ return jsRegionKindForDeclarationName(propertyName, source) ?? (context.regionKind === 'type' ? 'property' : context.regionKind) ?? 'property';
240
+ }
241
+
182
242
  function jsInlineClassMemberDeclarations(input, lineNumber, declarationLine, className) {
183
243
  const open = declarationLine.indexOf('{');
184
244
  const close = declarationLine.lastIndexOf('}');
@@ -3,6 +3,7 @@ import type { NativeImportRegionTaxonomyKind } from './index.js';
3
3
 
4
4
  export type SemanticImportImpactRisk = 'low' | 'medium' | 'high' | string;
5
5
  export type SemanticImportImpactConfidence = 'source-exact' | 'source-addressed' | 'estimated-source-region' | 'review-required' | string;
6
+ export type SemanticImportMergeSignalStatus = 'strong' | 'partial' | 'weak' | 'blocked' | string;
6
7
 
7
8
  export interface SemanticImportImpactVerificationStep {
8
9
  readonly kind: 'dependency-review' | 'source-map-review' | 'reject-or-reprove' | 'proof-review' | 'patch-admission' | 'evidence-review' | string;
@@ -10,6 +11,20 @@ export interface SemanticImportImpactVerificationStep {
10
11
  readonly required: boolean;
11
12
  }
12
13
 
14
+ export interface SemanticImportMergeSignal {
15
+ readonly status: SemanticImportMergeSignalStatus;
16
+ readonly score: number;
17
+ readonly missing: readonly string[];
18
+ readonly reviewRequired: boolean;
19
+ readonly queryKeys: readonly string[];
20
+ }
21
+
22
+ export interface SemanticImportMergeSignalScoreSummary {
23
+ readonly min: number;
24
+ readonly max: number;
25
+ readonly average: number;
26
+ }
27
+
13
28
  export interface SemanticImportImpactRecord {
14
29
  readonly id: string;
15
30
  readonly kind: 'ownership-region-impact' | string;
@@ -39,6 +54,7 @@ export interface SemanticImportImpactRecord {
39
54
  readonly readiness: SemanticMergeReadiness;
40
55
  readonly risk: SemanticImportImpactRisk;
41
56
  readonly confidence: SemanticImportImpactConfidence;
57
+ readonly mergeSignal: SemanticImportMergeSignal;
42
58
  }
43
59
 
44
60
  export interface SemanticImportImpactSummary {
@@ -63,5 +79,10 @@ export interface SemanticImportImpactSummary {
63
79
  readonly evidenceIds: number;
64
80
  readonly verificationPlans: readonly string[];
65
81
  readonly requiredVerificationSteps: number;
82
+ readonly byMergeSignal: Readonly<Record<string, number>>;
83
+ readonly weakMergeSignals: number;
84
+ readonly reviewRequiredMergeSignals: number;
85
+ readonly mergeSignalQueryKeys: readonly string[];
86
+ readonly mergeSignalScores: SemanticImportMergeSignalScoreSummary;
66
87
  };
67
88
  }
@@ -1,5 +1,6 @@
1
1
  import { countBy, idFragment, maxSemanticMergeReadiness, uniqueRecordsById, uniqueStrings } from './native-import-utils.js';
2
2
  import { semanticDependencyPredicateKey } from './semantic-import-dependencies.js';
3
+ import { semanticImpactMergeSignal, summarizeSemanticImpactMergeSignals } from './semantic-import-merge-signal.js';
3
4
 
4
5
  function createSemanticImportImpact(input) {
5
6
  const relations = collectDependencyRelations(input.imports, input.dependencies);
@@ -60,7 +61,7 @@ function semanticImpactRecord(input) {
60
61
  relationCount: input.relations.length,
61
62
  verificationPlan
62
63
  });
63
- return {
64
+ const record = {
64
65
  id: `impact_${idFragment(input.region.id ?? input.region.key)}`,
65
66
  kind: 'ownership-region-impact',
66
67
  ownershipRegionId: input.region.id,
@@ -93,6 +94,7 @@ function semanticImpactRecord(input) {
93
94
  risk,
94
95
  confidence: semanticImpactConfidence(input.region, input.sourceMapMappings, input.sourcePreservationRecords)
95
96
  };
97
+ return { ...record, mergeSignal: semanticImpactMergeSignal(record) };
96
98
  }
97
99
 
98
100
  function collectDependencyRelations(imports, dependencies) {
@@ -299,7 +301,8 @@ function summarizeSemanticImpactRecords(records) {
299
301
  loweringRecords: uniqueStrings(records.flatMap((record) => record.loweringRecordIds)).length,
300
302
  evidenceIds: uniqueStrings(records.flatMap((record) => record.evidenceIds)).length,
301
303
  verificationPlans: uniqueStrings(verificationPlans),
302
- requiredVerificationSteps: records.flatMap((record) => record.verificationPlan).filter((step) => step.required).length
304
+ requiredVerificationSteps: records.flatMap((record) => record.verificationPlan).filter((step) => step.required).length,
305
+ ...summarizeSemanticImpactMergeSignals(records)
303
306
  };
304
307
  }
305
308
 
@@ -0,0 +1,86 @@
1
+ import { countBy, uniqueStrings } from './native-import-utils.js';
2
+
3
+ export function semanticImpactMergeSignal(record) {
4
+ const missing = semanticImpactMissingSignals(record);
5
+ const requiredSteps = (record.verificationPlan ?? []).filter((step) => step.required).length;
6
+ const blocked = record.readiness === 'blocked' || (record.failedProofObligationIds ?? []).length > 0;
7
+ const reviewRequired = blocked || record.readiness !== 'ready' || record.risk !== 'low' || requiredSteps > 0 || missing.length > 0;
8
+ const score = semanticImpactMergeScore(record, missing, requiredSteps, blocked);
9
+ const status = semanticImpactMergeStatus(record, score, blocked);
10
+ return {
11
+ status,
12
+ score,
13
+ missing,
14
+ reviewRequired,
15
+ queryKeys: semanticImpactMergeQueryKeys(record, status, missing, reviewRequired)
16
+ };
17
+ }
18
+
19
+ export function summarizeSemanticImpactMergeSignals(records) {
20
+ const signals = (records ?? []).map((record) => record.mergeSignal).filter(Boolean);
21
+ return {
22
+ byMergeSignal: countBy(signals.map((signal) => signal.status)),
23
+ weakMergeSignals: signals.filter((signal) => signal.status === 'weak' || signal.status === 'blocked').length,
24
+ reviewRequiredMergeSignals: signals.filter((signal) => signal.reviewRequired).length,
25
+ mergeSignalQueryKeys: uniqueStrings(signals.flatMap((signal) => signal.queryKeys)),
26
+ mergeSignalScores: semanticImpactMergeScoreSummary(signals)
27
+ };
28
+ }
29
+
30
+ function semanticImpactMissingSignals(record) {
31
+ const missing = [];
32
+ if ((record.evidenceIds ?? []).length === 0) missing.push('evidence');
33
+ if ((record.sourceMapMappingIds ?? []).length === 0) missing.push('source-map');
34
+ if ((record.sourcePreservationRecordIds ?? []).length === 0) missing.push('source-preservation');
35
+ if (record.readiness !== 'ready' && (record.patchHintIds ?? []).length === 0) missing.push('patch-hint');
36
+ if ((record.openProofObligationIds ?? []).length > 0) missing.push('proof-obligations');
37
+ if (record.confidence === 'estimated-source-region' || record.confidence === 'review-required') missing.push('source-confidence');
38
+ return uniqueStrings(missing);
39
+ }
40
+
41
+ function semanticImpactMergeScore(record, missing, requiredSteps, blocked) {
42
+ let score = 100;
43
+ if (blocked) score -= 70;
44
+ else if (record.risk === 'high') score -= 35;
45
+ else if (record.risk === 'medium') score -= 18;
46
+ if (record.readiness === 'blocked') score -= 30;
47
+ else if (record.readiness === 'needs-review') score -= 18;
48
+ else if (record.readiness === 'ready-with-losses') score -= 8;
49
+ score -= Math.min(requiredSteps * 8, 32);
50
+ score -= Math.min(missing.length * 7, 35);
51
+ if ((record.failedProofObligationIds ?? []).length > 0) score -= 30;
52
+ if ((record.openProofObligationIds ?? []).length > 0) score -= 12;
53
+ if (record.confidence === 'source-exact') score += 5;
54
+ return Math.max(0, Math.min(100, Math.round(score)));
55
+ }
56
+
57
+ function semanticImpactMergeStatus(record, score, blocked) {
58
+ if (blocked || score < 25) return 'blocked';
59
+ if (score < 50 || record.risk === 'high') return 'weak';
60
+ if (score < 80 || record.risk === 'medium' || record.readiness !== 'ready') return 'partial';
61
+ return 'strong';
62
+ }
63
+
64
+ function semanticImpactMergeQueryKeys(record, status, missing, reviewRequired) {
65
+ return uniqueStrings([
66
+ `merge-signal:${status}`,
67
+ `risk:${record.risk ?? 'unknown'}`,
68
+ `readiness:${record.readiness ?? 'unknown'}`,
69
+ reviewRequired ? 'review-required' : 'review-not-required',
70
+ ...missing.map((item) => `missing:${item}`),
71
+ record.sourcePath ? `source:${record.sourcePath}` : undefined,
72
+ record.ownershipKey ? `ownership:${record.ownershipKey}` : undefined,
73
+ ...(record.symbolNames ?? []).map((name) => `symbol-name:${name}`),
74
+ ...(record.dependencyPredicates ?? []).map((predicate) => `predicate:${predicate}`)
75
+ ].filter(Boolean));
76
+ }
77
+
78
+ function semanticImpactMergeScoreSummary(signals) {
79
+ if (!signals.length) return { min: 0, max: 0, average: 0 };
80
+ const scores = signals.map((signal) => signal.score);
81
+ return {
82
+ min: Math.min(...scores),
83
+ max: Math.max(...scores),
84
+ average: Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length)
85
+ };
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.68",
3
+ "version": "0.2.70",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",