@shapeshift-labs/frontier-lang-compiler 0.2.154 → 0.2.156
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/dist/declarations/js-ts-project-merge-confidence.d.ts +5 -0
- package/dist/declarations/js-ts-safe-project-merge.d.ts +9 -9
- package/dist/internal/index-impl/projectSymbolGraphCssModuleMemberAccess.js +84 -0
- package/dist/internal/index-impl/projectSymbolGraphCssModuleScanners.js +78 -52
- package/dist/js-ts-safe-project-merge-missing-evidence.js +11 -1
- package/dist/js-ts-safe-project-merge-summary.js +6 -6
- package/dist/js-ts-safe-project-merge.js +2 -2
- package/package.json +1 -1
|
@@ -34,6 +34,10 @@ export interface JsTsProjectSafeMergeMissingEvidence {
|
|
|
34
34
|
readonly semanticEquivalenceClaim: false;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export type JsTsProjectSafeMergeAdmissionMatrixSurface = Record<string, unknown> & { readonly surface: string; readonly proofStatuses: Readonly<Record<string, string>>; readonly missingRouteIds?: readonly string[]; readonly nextMissingRouteId?: string };
|
|
38
|
+
|
|
39
|
+
export type JsTsProjectSafeMergeAdmissionMatrixAudit = Record<string, unknown> & { readonly kind: 'frontier.lang.jsTsProjectMergeAdmissionMatrixAudit'; readonly surfaces: readonly JsTsProjectSafeMergeAdmissionMatrixSurface[] };
|
|
40
|
+
|
|
37
41
|
export interface JsTsProjectSafeMergeConfidenceSummary {
|
|
38
42
|
readonly kind: 'frontier.lang.jsTsProjectMergeConfidence';
|
|
39
43
|
readonly version: 1;
|
|
@@ -59,6 +63,7 @@ export interface JsTsProjectSafeMergeConfidenceSummary {
|
|
|
59
63
|
readonly missingEvidence: readonly JsTsProjectSafeMergeMissingEvidence[];
|
|
60
64
|
readonly missingEvidenceMatrix: JsTsProjectSafeMergeMissingEvidenceTelemetry;
|
|
61
65
|
readonly routingCalibration: Record<string, unknown>;
|
|
66
|
+
readonly admissionMatrixAudit: JsTsProjectSafeMergeAdmissionMatrixAudit;
|
|
62
67
|
readonly dimensions: Readonly<Record<string, string>>;
|
|
63
68
|
readonly signals: Readonly<Record<string, number>>;
|
|
64
69
|
}
|
|
@@ -51,14 +51,14 @@ export interface JsTsProjectSafeMergeFileInput {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export type JsTsProjectSafeMergeFileMap =
|
|
54
|
-
| Readonly<Record<string,
|
|
54
|
+
| Readonly<Record<string,string | { readonly sourceText?: string; readonly text?: string; readonly parserTriviaEvidence?: ParserTriviaEvidenceInput }>>
|
|
55
55
|
| ReadonlyMap<string, string | { readonly sourceText?: string; readonly text?: string; readonly parserTriviaEvidence?: ParserTriviaEvidenceInput }>
|
|
56
56
|
| readonly { readonly sourcePath?: string; readonly path?: string; readonly sourceText?: string; readonly text?: string; readonly parserTriviaEvidence?: ParserTriviaEvidenceInput }[];
|
|
57
57
|
|
|
58
58
|
export type JsTsProjectSafeMergeOutputProjectImports =
|
|
59
59
|
| readonly NativeSourceImportResult[]
|
|
60
60
|
| ReadonlyMap<string, NativeSourceImportResult>
|
|
61
|
-
| Readonly<Record<string,
|
|
61
|
+
| Readonly<Record<string,NativeSourceImportResult>>;
|
|
62
62
|
|
|
63
63
|
export type JsTsProjectGraphStageName = 'base' | 'worker' | 'head' | 'output' | string;
|
|
64
64
|
|
|
@@ -133,8 +133,8 @@ export interface JsTsProjectSafeMergeInput {
|
|
|
133
133
|
readonly headChangeSetId?: string;
|
|
134
134
|
readonly policy?: JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[];
|
|
135
135
|
readonly mergePolicy?: JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[];
|
|
136
|
-
readonly policyByPath?: Readonly<Record<string,
|
|
137
|
-
readonly mergePolicyByPath?: Readonly<Record<string,
|
|
136
|
+
readonly policyByPath?: Readonly<Record<string,JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[]>>;
|
|
137
|
+
readonly mergePolicyByPath?: Readonly<Record<string,JsTsSafeMemberMergePolicy | readonly JsTsSafeMemberMergePolicyRegion[]>>;
|
|
138
138
|
readonly requireSourceLedgerSpans?: boolean;
|
|
139
139
|
readonly sourceLedgers?: Record<string, unknown>;
|
|
140
140
|
readonly sourceLedgersByPath?: Record<string, Record<string, unknown>>;
|
|
@@ -244,13 +244,13 @@ export interface JsTsProjectGraphDeltaSummary {
|
|
|
244
244
|
readonly reExportIdentityConflicts: number; readonly moduleDeclarationShapeConflicts: number; readonly exportAssignmentShapeConflicts: number;
|
|
245
245
|
readonly importAttributeConflicts: number;
|
|
246
246
|
readonly importTargetConflicts: number;
|
|
247
|
-
readonly stageSummaries: Readonly<Record<string,
|
|
247
|
+
readonly stageSummaries: Readonly<Record<string,JsTsProjectGraphDeltaStageSummary>>;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
export interface JsTsProjectGraphDelta {
|
|
251
251
|
readonly kind: 'frontier.lang.jsTsProjectGraphDelta';
|
|
252
252
|
readonly version: 1;
|
|
253
|
-
readonly stages: Readonly<Record<string,
|
|
253
|
+
readonly stages: Readonly<Record<string,JsTsProjectGraphDeltaStage>>;
|
|
254
254
|
readonly summary: JsTsProjectGraphDeltaSummary;
|
|
255
255
|
}
|
|
256
256
|
|
|
@@ -279,7 +279,7 @@ export interface JsTsProjectSafeMergeResult {
|
|
|
279
279
|
readonly outputFiles: number;
|
|
280
280
|
readonly projectGraphConflicts: number;
|
|
281
281
|
readonly projectGraphDeltaEvidenceIncluded: number;
|
|
282
|
-
|
|
282
|
+
outputProjectGraphConflicts:number; projectGraphCssModuleUseSiteConflicts:number;
|
|
283
283
|
readonly projectGraphDeltaConflicts: number;
|
|
284
284
|
readonly projectGraphLimitConflicts: number;
|
|
285
285
|
readonly projectGraphPublicContractConflicts: number;
|
|
@@ -297,11 +297,11 @@ export interface JsTsProjectSafeMergeResult {
|
|
|
297
297
|
readonly outputDeclarationConflicts: number;
|
|
298
298
|
readonly outputDeclarationDiagnosticErrors: number;
|
|
299
299
|
readonly outputQualityGates: number; readonly outputQualityGateConflicts: number;
|
|
300
|
-
readonly proofEvidenceRecords: number; readonly proofEvidencePassed: number; readonly proofEvidenceFailed: number; readonly proofEvidenceSkipped: number; readonly proofEvidenceUnknown: number; readonly proofEvidenceMissing: number; readonly proofEvidenceMissingLevels: readonly JsTsProjectMergeProofLevel[]; readonly semanticEquivalenceLevel: 'semantic-equivalence-unknown' | string; readonly evidenceRecords: number; readonly passedEvidenceRecords: number; readonly failedEvidenceRecords: number; readonly unknownEvidenceRecords: number; readonly confidenceScore: number; readonly confidenceLevel: string; readonly confidenceDimensions: Readonly<Record<string,
|
|
300
|
+
readonly proofEvidenceRecords: number; readonly proofEvidencePassed: number; readonly proofEvidenceFailed: number; readonly proofEvidenceSkipped: number; readonly proofEvidenceUnknown: number; readonly proofEvidenceMissing: number; readonly proofEvidenceMissingLevels: readonly JsTsProjectMergeProofLevel[]; readonly semanticEquivalenceLevel: 'semantic-equivalence-unknown' | string; readonly evidenceRecords: number; readonly passedEvidenceRecords: number; readonly failedEvidenceRecords: number; readonly unknownEvidenceRecords: number; readonly confidenceScore: number; readonly confidenceLevel: string; readonly confidenceDimensions: Readonly<Record<string,string>>; readonly missingEvidenceMatrix: JsTsProjectSafeMergeMissingEvidenceTelemetry; readonly missingSignals: number; readonly nextMissingEvidenceCode?: string; readonly nextMissingEvidenceKind?: string; readonly nextMissingEvidenceScope?: string; readonly nextMissingProofLevel?: string; readonly nextMissingEvidenceAction?: string; readonly nextMissingEvidenceRouteId?: string; readonly nextMissingEvidenceRouteLane?: string; readonly nextMissingEvidenceRouteNext?: string;
|
|
301
301
|
readonly projectMoveRenameClassifications: number; readonly projectFileMoveRenameClassifications: number; readonly projectSymbolMoveClassifications: number; readonly projectExportedSymbolMoveClassifications: number; readonly projectImportedSymbolMoveClassifications: number; readonly projectSymbolMoveAdmissions: number; readonly projectExportedSymbolMoveAdmissions: number; readonly projectImportedSymbolMoveAdmissions: number; readonly projectCrossFileSymbolRenameClassifications: number; readonly projectCrossFileSymbolRenameAdmissions: number;
|
|
302
302
|
readonly projectSplitMergeClassifications: number; readonly projectModuleSplitClassifications: number; readonly projectModuleMergeClassifications: number; readonly projectClassSplitClassifications: number; readonly projectClassMergeClassifications: number; readonly projectSplitMergeAdmissions: number; readonly projectModuleSplitAdmissions: number; readonly projectModuleMergeAdmissions: number; readonly projectClassSplitAdmissions: number; readonly projectClassMergeAdmissions: number;
|
|
303
303
|
readonly semanticArtifactFiles: number;
|
|
304
|
-
readonly operations: Readonly<Record<string,
|
|
304
|
+
readonly operations: Readonly<Record<string,number>>;
|
|
305
305
|
};
|
|
306
306
|
readonly metadata?: Record<string, unknown> & {
|
|
307
307
|
readonly projectMoveRenameClassifications?: {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { readStaticMemberLiteral } from './staticMemberLiteral.js';
|
|
2
|
+
import { escapeRegExp, isIdentifierChar } from './projectSymbolGraphCssModuleUtils.js';
|
|
3
|
+
|
|
4
|
+
const IdentifierPattern = /^[A-Za-z_$][\w$]*$/;
|
|
5
|
+
|
|
6
|
+
function cssModuleMemberAccess(sourceText, receiverEnd) {
|
|
7
|
+
let index = receiverEnd;
|
|
8
|
+
while (index < sourceText.length && /\s/.test(sourceText[index])) index += 1;
|
|
9
|
+
if (sourceText[index] === '?' && sourceText[index + 1] === '.') index += 2;
|
|
10
|
+
else if (sourceText[index] === '.') index += 1;
|
|
11
|
+
else if (sourceText[index] === '[') return cssModuleComputedAccess(sourceText, index);
|
|
12
|
+
else return undefined;
|
|
13
|
+
while (index < sourceText.length && /\s/.test(sourceText[index])) index += 1;
|
|
14
|
+
const match = /^[A-Za-z_$][\w$]*/.exec(sourceText.slice(index));
|
|
15
|
+
return match ? { accessKind: 'dot', memberName: match[0], end: index + match[0].length } : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function cssModuleComputedAccess(sourceText, open) {
|
|
19
|
+
const close = findMatchingBracket(sourceText, open);
|
|
20
|
+
if (close === -1) return { status: 'blocked', reasonCode: 'css-module-dynamic-member-access-unproved', end: open + 1 };
|
|
21
|
+
let index = open + 1;
|
|
22
|
+
while (index < close && /\s/.test(sourceText[index])) index += 1;
|
|
23
|
+
const literal = readStaticMemberLiteral(sourceText, index, close);
|
|
24
|
+
if (!literal || !IdentifierPattern.test(literal.value)) {
|
|
25
|
+
return { status: 'blocked', reasonCode: 'css-module-dynamic-member-access-unproved', end: close + 1, expressionText: sourceText.slice(open, close + 1) };
|
|
26
|
+
}
|
|
27
|
+
return { accessKind: literal.literalKind === 'static-template-literal' ? 'static-template' : 'static-bracket', memberName: literal.value, end: close + 1 };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function cssModuleStaticExpressionAccess(expressionText, localName) {
|
|
31
|
+
const value = String(expressionText ?? '').trim();
|
|
32
|
+
if (!value.startsWith(localName)) return undefined;
|
|
33
|
+
if (isIdentifierChar(value[localName.length])) return undefined;
|
|
34
|
+
const access = cssModuleMemberAccess(value, localName.length);
|
|
35
|
+
if (!access || access.status === 'blocked' || access.end !== value.length) return undefined;
|
|
36
|
+
return {
|
|
37
|
+
accessKind: access.accessKind,
|
|
38
|
+
memberName: access.memberName,
|
|
39
|
+
optional: /\?\./.test(value.slice(0, access.end))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function cssModuleExpressionHasCall(expressionText) {
|
|
44
|
+
const value = String(expressionText ?? '');
|
|
45
|
+
return /\?\.\s*\(/.test(value) || /\b[A-Za-z_$][\w$]*(?:\s*(?:\.|\?\.)\s*[A-Za-z_$][\w$]*)*\s*\(/.test(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function cssModuleExpressionHasBlockedAccess(expressionText, localName) {
|
|
49
|
+
const value = String(expressionText ?? '');
|
|
50
|
+
for (const occurrence of identifierOccurrences(value, localName)) {
|
|
51
|
+
const access = cssModuleMemberAccess(value, occurrence.end);
|
|
52
|
+
if (access?.status === 'blocked') return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function identifierOccurrences(sourceText, name) {
|
|
58
|
+
const result = [];
|
|
59
|
+
const pattern = new RegExp(`\\b${escapeRegExp(name)}\\b`, 'g');
|
|
60
|
+
for (const match of sourceText.matchAll(pattern)) {
|
|
61
|
+
const start = match.index;
|
|
62
|
+
const end = start + name.length;
|
|
63
|
+
if (isIdentifierChar(sourceText[start - 1]) || isIdentifierChar(sourceText[end])) continue;
|
|
64
|
+
result.push({ start, end });
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function findMatchingBracket(sourceText, open) {
|
|
70
|
+
let depth = 0;
|
|
71
|
+
for (let index = open; index < sourceText.length; index += 1) {
|
|
72
|
+
if (sourceText[index] === '[') depth += 1;
|
|
73
|
+
else if (sourceText[index] === ']' && --depth === 0) return index;
|
|
74
|
+
}
|
|
75
|
+
return -1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
cssModuleExpressionHasBlockedAccess,
|
|
80
|
+
cssModuleExpressionHasCall,
|
|
81
|
+
cssModuleMemberAccess,
|
|
82
|
+
cssModuleStaticExpressionAccess,
|
|
83
|
+
identifierOccurrences
|
|
84
|
+
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { readStaticMemberLiteral } from './staticMemberLiteral.js';
|
|
2
1
|
import {
|
|
3
2
|
bindingsForSourcePath,
|
|
4
3
|
escapeRegExp,
|
|
5
|
-
isIdentifierChar,
|
|
6
4
|
localKey,
|
|
7
5
|
sourceSpanForRange
|
|
8
6
|
} from './projectSymbolGraphCssModuleUtils.js';
|
|
@@ -11,8 +9,13 @@ import {
|
|
|
11
9
|
cssModulePropBlocker,
|
|
12
10
|
cssModuleUseSiteRecord
|
|
13
11
|
} from './projectSymbolGraphCssModuleRecords.js';
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
import {
|
|
13
|
+
cssModuleExpressionHasBlockedAccess,
|
|
14
|
+
cssModuleExpressionHasCall,
|
|
15
|
+
cssModuleMemberAccess,
|
|
16
|
+
cssModuleStaticExpressionAccess,
|
|
17
|
+
identifierOccurrences
|
|
18
|
+
} from './projectSymbolGraphCssModuleMemberAccess.js';
|
|
16
19
|
|
|
17
20
|
function cssModuleLexicalUseSites(importBindings, sourceTextsByPath) {
|
|
18
21
|
const useSites = [];
|
|
@@ -99,13 +102,15 @@ function cssModuleJsxUseSites(bindingsByLocal, jsxPropRecords) {
|
|
|
99
102
|
useSites.push(...cssModuleJsxStaticUseSites(sourceBindings, prop));
|
|
100
103
|
const classNameBindings = bindingsForSourcePath(bindingsByLocal, prop.sourcePath);
|
|
101
104
|
if (prop.propName !== 'className' || !classNameBindings.length) continue;
|
|
105
|
+
useSites.push(...cssModuleJsxStaticComputedUseSites(classNameBindings, prop));
|
|
106
|
+
useSites.push(...cssModuleJsxHelperUseSites(classNameBindings, prop));
|
|
102
107
|
blockers.push(...cssModuleJsxBlockers(classNameBindings, prop));
|
|
103
108
|
}
|
|
104
109
|
return { useSites, blockers };
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
function cssModuleJsxStaticUseSites(sourceBindings, prop) {
|
|
108
|
-
if (prop.propName !== 'className' || prop.propValueKind !== 'reference') return [];
|
|
113
|
+
if (prop.propName !== 'className' || (prop.propValueKind !== 'reference' && prop.propValueKind !== 'optional-reference')) return [];
|
|
109
114
|
const referencePath = prop.propValueReferencePath ?? [];
|
|
110
115
|
if (referencePath.length < 2) return [];
|
|
111
116
|
return sourceBindings.map((binding) => cssModuleUseSiteRecord(binding, {
|
|
@@ -117,43 +122,75 @@ function cssModuleJsxStaticUseSites(sourceBindings, prop) {
|
|
|
117
122
|
sourcePath: prop.sourcePath,
|
|
118
123
|
sourceHash: prop.sourceHash,
|
|
119
124
|
sourceSpan: prop.sourceSpan,
|
|
120
|
-
jsxPropRecordId: prop.id
|
|
125
|
+
jsxPropRecordId: prop.id,
|
|
126
|
+
conditionalRuntimePresence: prop.propValueKind === 'optional-reference' || undefined
|
|
121
127
|
}));
|
|
122
128
|
}
|
|
123
129
|
|
|
124
|
-
function
|
|
125
|
-
if (prop.propValueKind === '
|
|
126
|
-
return classNameBindings.map((binding) => cssModulePropBlocker(binding, prop, 'css-module-string-literal-classname-unproved'));
|
|
127
|
-
}
|
|
128
|
-
if (!prop.propValueDynamicBlockerReasonCode) return [];
|
|
130
|
+
function cssModuleJsxStaticComputedUseSites(classNameBindings, prop) {
|
|
131
|
+
if (prop.propValueKind === 'reference' || prop.propValueKind === 'optional-reference') return [];
|
|
129
132
|
const expressionText = prop.propValueExpressionText ?? prop.propValueDynamicText ?? '';
|
|
130
|
-
return classNameBindings
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
return classNameBindings.flatMap((binding) => {
|
|
134
|
+
const access = cssModuleStaticExpressionAccess(expressionText, binding.localName);
|
|
135
|
+
if (!access) return [];
|
|
136
|
+
return [cssModuleUseSiteRecord(binding, {
|
|
137
|
+
useSiteKind: 'jsx-className',
|
|
138
|
+
accessKind: access.accessKind,
|
|
139
|
+
exportName: access.memberName,
|
|
140
|
+
receiverLocalName: binding.localName,
|
|
141
|
+
expressionText,
|
|
142
|
+
sourcePath: prop.sourcePath,
|
|
143
|
+
sourceHash: prop.sourceHash,
|
|
144
|
+
sourceSpan: prop.sourceSpan,
|
|
145
|
+
jsxPropRecordId: prop.id,
|
|
146
|
+
conditionalRuntimePresence: access.optional || undefined
|
|
147
|
+
})];
|
|
148
|
+
});
|
|
133
149
|
}
|
|
134
150
|
|
|
135
|
-
function
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
151
|
+
function cssModuleJsxHelperUseSites(classNameBindings, prop) {
|
|
152
|
+
const expressionText = prop.propValueExpressionText ?? prop.propValueDynamicText ?? '';
|
|
153
|
+
if (!cssModuleExpressionHasCall(expressionText)) return [];
|
|
154
|
+
const useSites = [];
|
|
155
|
+
for (const binding of classNameBindings) {
|
|
156
|
+
for (const occurrence of identifierOccurrences(expressionText, binding.localName)) {
|
|
157
|
+
const access = cssModuleMemberAccess(expressionText, occurrence.end);
|
|
158
|
+
if (!access || access.status === 'blocked') continue;
|
|
159
|
+
if (memberWriteOperation(expressionText, occurrence.start, access.end)) continue;
|
|
160
|
+
useSites.push(cssModuleUseSiteRecord(binding, {
|
|
161
|
+
useSiteKind: 'jsx-className-helper',
|
|
162
|
+
accessKind: access.accessKind,
|
|
163
|
+
exportName: access.memberName,
|
|
164
|
+
receiverLocalName: binding.localName,
|
|
165
|
+
expressionText: expressionText.slice(occurrence.start, access.end),
|
|
166
|
+
sourcePath: prop.sourcePath,
|
|
167
|
+
sourceHash: prop.sourceHash,
|
|
168
|
+
sourceSpan: prop.sourceSpan,
|
|
169
|
+
jsxPropRecordId: prop.id,
|
|
170
|
+
conditionalRuntimePresence: cssModuleHelperArgumentIsConditional(expressionText, occurrence.start) || undefined
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return useSites;
|
|
145
175
|
}
|
|
146
176
|
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
let index = open + 1;
|
|
151
|
-
while (index < close && /\s/.test(sourceText[index])) index += 1;
|
|
152
|
-
const literal = readStaticMemberLiteral(sourceText, index, close);
|
|
153
|
-
if (!literal || !IdentifierPattern.test(literal.value)) {
|
|
154
|
-
return { status: 'blocked', reasonCode: 'css-module-dynamic-member-access-unproved', end: close + 1, expressionText: sourceText.slice(open, close + 1) };
|
|
177
|
+
function cssModuleJsxBlockers(classNameBindings, prop) {
|
|
178
|
+
if (prop.propValueKind === 'string') {
|
|
179
|
+
return classNameBindings.map((binding) => cssModulePropBlocker(binding, prop, 'css-module-string-literal-classname-unproved'));
|
|
155
180
|
}
|
|
156
|
-
|
|
181
|
+
const expressionText = prop.propValueExpressionText ?? prop.propValueDynamicText ?? '';
|
|
182
|
+
if (!expressionText) return [];
|
|
183
|
+
return classNameBindings.flatMap((binding) => {
|
|
184
|
+
if (!expressionText.includes(binding.localName)) return [];
|
|
185
|
+
const reasonCodes = [];
|
|
186
|
+
if (cssModuleExpressionHasCall(expressionText)) reasonCodes.push('css-module-helper-call-unproved');
|
|
187
|
+
if (cssModuleExpressionHasBlockedAccess(expressionText, binding.localName)) reasonCodes.push('css-module-dynamic-member-access-unproved');
|
|
188
|
+
if (!reasonCodes.length && cssModuleStaticExpressionAccess(expressionText, binding.localName)) return [];
|
|
189
|
+
if (!reasonCodes.length && prop.propValueDynamicBlockerReasonCode) {
|
|
190
|
+
reasonCodes.push(jsxDynamicReason(prop.propValueDynamicBlockerReasonCode));
|
|
191
|
+
}
|
|
192
|
+
return [...new Set(reasonCodes)].map((reasonCode) => cssModulePropBlocker(binding, prop, reasonCode));
|
|
193
|
+
});
|
|
157
194
|
}
|
|
158
195
|
|
|
159
196
|
function memberWriteOperation(sourceText, start, end) {
|
|
@@ -183,15 +220,6 @@ function hasPrefixUpdateOperator(code, tokenStart) {
|
|
|
183
220
|
return before < 0 || !/[A-Za-z0-9_$)\]]/.test(code[before]);
|
|
184
221
|
}
|
|
185
222
|
|
|
186
|
-
function findMatchingBracket(sourceText, open) {
|
|
187
|
-
let depth = 0;
|
|
188
|
-
for (let index = open; index < sourceText.length; index += 1) {
|
|
189
|
-
if (sourceText[index] === '[') depth += 1;
|
|
190
|
-
else if (sourceText[index] === ']' && --depth === 0) return index;
|
|
191
|
-
}
|
|
192
|
-
return -1;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
223
|
function destructuringProperty(text) {
|
|
196
224
|
const value = String(text ?? '').trim();
|
|
197
225
|
const [rawName, rawLocal] = value.split(':').map((part) => part.trim());
|
|
@@ -221,16 +249,14 @@ function splitTopLevelComma(text, baseOffset) {
|
|
|
221
249
|
return parts;
|
|
222
250
|
}
|
|
223
251
|
|
|
224
|
-
function
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
return result;
|
|
252
|
+
function cssModuleHelperArgumentIsConditional(expressionText, occurrenceStart) {
|
|
253
|
+
const prefix = expressionText.slice(0, occurrenceStart);
|
|
254
|
+
const suffix = expressionText.slice(occurrenceStart);
|
|
255
|
+
const lastComma = prefix.lastIndexOf(',');
|
|
256
|
+
const argumentPrefix = prefix.slice(lastComma + 1);
|
|
257
|
+
const nextComma = suffix.indexOf(',');
|
|
258
|
+
const argumentText = `${argumentPrefix}${nextComma === -1 ? suffix : suffix.slice(0, nextComma)}`;
|
|
259
|
+
return /(?:&&|\|\||\?)/.test(argumentText);
|
|
234
260
|
}
|
|
235
261
|
|
|
236
262
|
function jsxDynamicReason(reasonCode) {
|
|
@@ -10,6 +10,7 @@ const ProjectMergeMissingSignals = Object.freeze({
|
|
|
10
10
|
semanticEditReplayProof: 'semantic-edit-replay-proof-not-produced',
|
|
11
11
|
semanticEditReplayOutputMismatch: 'semantic-edit-replay-proof-output-mismatch',
|
|
12
12
|
unsupportedJsTsSurface: 'unsupported-js-ts-surface-proof-not-available',
|
|
13
|
+
cssModuleUseSiteGraph: 'css-module-use-site-graph-proof-blocked',
|
|
13
14
|
semanticEquivalenceProof: 'semantic-equivalence-proof-not-available'
|
|
14
15
|
});
|
|
15
16
|
|
|
@@ -25,6 +26,7 @@ const ProjectMergeMissingEvidenceRoutes = Object.freeze({
|
|
|
25
26
|
[ProjectMergeMissingSignals.semanticEditReplayProof]: route('produce-semantic-edit-replay-proof', 'source-files', 'run-semantic-edit-replay-diagnostics'),
|
|
26
27
|
[ProjectMergeMissingSignals.semanticEditReplayOutputMismatch]: route('reject-semantic-edit-replay-output-mismatch', 'source-files', 'inspect-semantic-edit-replay-output-binding'),
|
|
27
28
|
[ProjectMergeMissingSignals.unsupportedJsTsSurface]: route('prove-unsupported-js-ts-surface', 'semantic-proof', 'supply-unsupported-surface-evidence'),
|
|
29
|
+
[ProjectMergeMissingSignals.cssModuleUseSiteGraph]: route('prove-css-module-use-site-graph', 'layout-style-graph', 'supply-css-module-transform-and-use-site-proof'),
|
|
28
30
|
[ProjectMergeMissingSignals.semanticEquivalenceProof]: route('external-semantic-equivalence-proof', 'semantic-proof', 'attach-external-equivalence-proof')
|
|
29
31
|
});
|
|
30
32
|
|
|
@@ -37,6 +39,7 @@ const ProjectMergeAdmissionMatrixRows = Object.freeze([
|
|
|
37
39
|
matrixRow('control-flow-effect-graph', 'partial', ['source-span-roundtrip', 'focused-test-passed'], [ProjectMergeMissingSignals.sourceSpanRoundtrip, ProjectMergeMissingSignals.semanticArtifacts, ProjectMergeMissingSignals.qualityGates, ProjectMergeMissingSignals.focusedTestGate]),
|
|
38
40
|
matrixRow('generic-semantic-edit-admission', 'partial', ['source-span-roundtrip', 'semantic-edit-replay-clean'], [ProjectMergeMissingSignals.sourceSpanRoundtrip, ProjectMergeMissingSignals.semanticArtifacts, ProjectMergeMissingSignals.semanticEditReplayProof, ProjectMergeMissingSignals.semanticEditReplayOutputMismatch]),
|
|
39
41
|
matrixRow('unsupported-js-ts-surface-coverage', 'partial', ['unsupported-js-ts-surface-review'], [ProjectMergeMissingSignals.unsupportedJsTsSurface]),
|
|
42
|
+
matrixRow('css-modules-use-site-graph', 'partial', ['css-module-use-site-graph', 'css-module-transform-proof', 'project-graph-evidence'], [ProjectMergeMissingSignals.cssModuleUseSiteGraph]),
|
|
40
43
|
matrixRow('semantic-equivalence-proof', 'bounded-evidence', ['semantic-equivalence-external', 'semantic-equivalence-unknown'], [ProjectMergeMissingSignals.semanticEquivalenceProof]),
|
|
41
44
|
matrixRow('cross-file-symbol-rename', 'partial', ['diagnostics-clean', 'declaration-output-stable', 'project-graph-delta'], [ProjectMergeMissingSignals.outputDiagnosticsGate, ProjectMergeMissingSignals.declarationGate, ProjectMergeMissingSignals.projectGraphEvidence, ProjectMergeMissingSignals.projectGraphDeltaEvidence]),
|
|
42
45
|
matrixRow('symbol-move-between-files', 'partial', ['diagnostics-clean', 'declaration-output-stable', 'project-graph-delta'], [ProjectMergeMissingSignals.outputDiagnosticsGate, ProjectMergeMissingSignals.declarationGate, ProjectMergeMissingSignals.projectGraphEvidence, ProjectMergeMissingSignals.projectGraphDeltaEvidence]),
|
|
@@ -127,6 +130,11 @@ function missingEvidenceItems(summary, context = {}) {
|
|
|
127
130
|
action: 'review',
|
|
128
131
|
summary: 'Executable semantic equivalence is still unknown; keep semanticEquivalenceClaim false and require human or external proof for equivalence claims.'
|
|
129
132
|
}));
|
|
133
|
+
if (summary.projectGraphCssModuleUseSiteConflicts) items.push(missingEvidenceItem({
|
|
134
|
+
code: ProjectMergeMissingSignals.cssModuleUseSiteGraph, scope: 'layout-style-graph', kind: 'css-module-use-site-proof', proofLevel: 'css-module-use-site-graph', action: 'review',
|
|
135
|
+
summary: `CSS Module use-site graph has ${summary.projectGraphCssModuleUseSiteConflicts} blocker(s); supply generated class maps, bundler transform identity, source-map proof, and narrow use-site evidence before admission.`,
|
|
136
|
+
suggestedInput: { includeOutputProjectSymbolGraph: true, cssModuleEvidence: true }
|
|
137
|
+
}));
|
|
130
138
|
return items;
|
|
131
139
|
}
|
|
132
140
|
|
|
@@ -240,7 +248,9 @@ function matrixProofStatus(level, summary, proofEvidence) {
|
|
|
240
248
|
const levelStatuses = proofEvidence?.summary?.levelStatuses ?? summary.proofEvidenceLevelStatuses ?? {};
|
|
241
249
|
if (levelStatuses[level]) return levelStatuses[level];
|
|
242
250
|
if (level === 'project-graph-delta') return summary.projectGraphDeltaEvidenceIncluded ? (summary.projectGraphDeltaConflicts ? 'failed' : 'passed') : 'missing';
|
|
243
|
-
if (level === 'project-graph-evidence') return summary.projectGraphConflicts ? 'failed' : summary.projectGraphDeltaEvidenceIncluded ? 'passed' : 'missing';
|
|
251
|
+
if (level === 'project-graph-evidence') return summary.projectGraphConflicts ? 'failed' : summary.projectGraphEvidenceIncluded || summary.projectGraphDeltaEvidenceIncluded ? 'passed' : 'missing';
|
|
252
|
+
if (level === 'css-module-use-site-graph') return summary.projectGraphCssModuleUseSiteConflicts ? 'failed' : summary.projectGraphCssModuleUseSiteGraphs ? 'passed' : summary.projectGraphEvidenceIncluded ? 'absent' : 'missing';
|
|
253
|
+
if (level === 'css-module-transform-proof') return summary.projectGraphCssModuleUseSiteConflicts ? 'failed' : summary.projectGraphCssModuleImportBindings ? 'passed' : summary.projectGraphEvidenceIncluded ? 'absent' : 'missing';
|
|
244
254
|
if (level === 'semantic-artifacts') return summary.semanticArtifactFiles ? 'present' : 'missing';
|
|
245
255
|
return 'absent';
|
|
246
256
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { compactMissingEvidenceTelemetry, confidenceRecommendedAction, createProjectMergeAdmissionMatrixAudit, missingEvidenceItems, missingEvidenceSignals, prioritizedMissingEvidence } from './js-ts-safe-project-merge-missing-evidence.js';
|
|
2
2
|
import { failedEvidenceMissingItems, fileAdmissionEvidenceRecords } from './js-ts-safe-project-merge-evidence-routing.js'; import { compactProjectMergeRoutingCalibration } from './js-ts-safe-project-merge-routing-calibration.js';
|
|
3
3
|
|
|
4
|
-
function projectSummary(files, graphConflicts = [], hasProjectGraphDelta = false, outputDiagnosticsGate = undefined, outputDeclarationGate = undefined, outputQualityGate = undefined, moveRenameSummary = undefined, proofEvidence = undefined, symbolRenameSummary = undefined, splitMergeSummary = undefined) {
|
|
4
|
+
function projectSummary(files, graphConflicts = [], hasProjectGraphDelta = false, outputDiagnosticsGate = undefined, outputDeclarationGate = undefined, outputQualityGate = undefined, moveRenameSummary = undefined, proofEvidence = undefined, symbolRenameSummary = undefined, splitMergeSummary = undefined, projectSymbolGraph = undefined) {
|
|
5
5
|
const byOperation = {};
|
|
6
6
|
for (const file of files) byOperation[file.operation] = (byOperation[file.operation] ?? 0) + 1;
|
|
7
7
|
const limitConflicts = graphConflicts.filter((conflict) => conflict.gateId === 'project-graph-limit');
|
|
8
8
|
const deltaConflicts = graphConflicts.filter((conflict) => conflict.gateId === 'project-graph-delta' || (hasProjectGraphDelta && conflict.gateId === 'project-graph-limit'));
|
|
9
|
-
const outputConflicts = graphConflicts.filter((conflict) => conflict.gateId === 'project-symbol-graph' || (!hasProjectGraphDelta && conflict.gateId === 'project-graph-limit'));
|
|
9
|
+
const outputConflicts = graphConflicts.filter((conflict) => conflict.gateId === 'project-symbol-graph' || (!hasProjectGraphDelta && conflict.gateId === 'project-graph-limit')), cssModuleConflicts = graphConflicts.filter((conflict) => conflict.gateId === 'project-css-module-use-site-graph');
|
|
10
10
|
const proofLevelStatuses = proofEvidence?.summary?.levelStatuses ?? {};
|
|
11
11
|
return {
|
|
12
12
|
files: files.length,
|
|
@@ -14,10 +14,10 @@ function projectSummary(files, graphConflicts = [], hasProjectGraphDelta = false
|
|
|
14
14
|
blockedFiles: files.filter((file) => file.status === 'blocked').length,
|
|
15
15
|
outputFiles: files.filter((file) => typeof file.outputSourceText === 'string').length,
|
|
16
16
|
projectGraphConflicts: graphConflicts.length,
|
|
17
|
-
projectGraphDeltaEvidenceIncluded: hasProjectGraphDelta ? 1 : 0,
|
|
18
|
-
outputProjectGraphConflicts: outputConflicts.length,
|
|
19
|
-
projectGraphDeltaConflicts: deltaConflicts.length,
|
|
20
|
-
projectGraphLimitConflicts: limitConflicts.length,
|
|
17
|
+
projectGraphDeltaEvidenceIncluded: hasProjectGraphDelta ? 1 : 0, projectGraphEvidenceIncluded: projectSymbolGraph || hasProjectGraphDelta ? 1 : 0,
|
|
18
|
+
outputProjectGraphConflicts: outputConflicts.length, projectGraphCssModuleUseSiteConflicts: cssModuleConflicts.length,
|
|
19
|
+
projectGraphDeltaConflicts: deltaConflicts.length, projectGraphCssModuleUseSiteBlockers: projectSymbolGraph?.cssModuleUseSiteBlockers?.length ?? cssModuleConflicts.length,
|
|
20
|
+
projectGraphLimitConflicts: limitConflicts.length, projectGraphCssModuleUseSiteGraphs: projectSymbolGraph?.cssModuleUseSiteGraphs?.length ?? 0, projectGraphCssModuleUseSites: projectSymbolGraph?.cssModuleUseSites?.length ?? 0, projectGraphCssModuleImportBindings: projectSymbolGraph?.cssModuleImportBindings?.length ?? 0,
|
|
21
21
|
projectGraphPublicContractConflicts: deltaConflicts.filter((conflict) => conflict.code === 'project-public-contract-delta-conflict').length,
|
|
22
22
|
projectGraphSourceSpanConflicts: deltaConflicts.filter((conflict) => conflict.code === 'project-source-span-delta-conflict').length,
|
|
23
23
|
projectGraphCompilerTypeConflicts: deltaConflicts.filter((conflict) => conflict.code === 'project-public-compiler-type-delta-conflict').length,
|
|
@@ -104,7 +104,7 @@ function safeMergeJsTsProject(input = {}) {
|
|
|
104
104
|
...fileResults.flatMap((file) => file.conflictKeys),
|
|
105
105
|
...outputConflicts.map((conflict) => conflict.details?.conflictKey)
|
|
106
106
|
]);
|
|
107
|
-
const baseSummary = projectSummary(fileResults, graphConflicts, Boolean(projectGraphDelta), outputDiagnosticsGate, outputDeclarationGate, outputQualityGate, moveRenameSummary, proofEvidence, symbolRenameSummary, splitMergeSummary);
|
|
107
|
+
const baseSummary = projectSummary(fileResults, graphConflicts, Boolean(projectGraphDelta), outputDiagnosticsGate, outputDeclarationGate, outputQualityGate, moveRenameSummary, proofEvidence, symbolRenameSummary, splitMergeSummary, graphArtifacts?.projectSymbolGraph);
|
|
108
108
|
const evidenceContext = {
|
|
109
109
|
fileResults,
|
|
110
110
|
outputDiagnosticsGate,
|
|
@@ -162,7 +162,7 @@ function safeMergeJsTsProject(input = {}) {
|
|
|
162
162
|
outputProjectSymbolGraph: Boolean(graphArtifacts?.projectSymbolGraph),
|
|
163
163
|
projectGraphDelta: Boolean(projectGraphDeltaWithConflicts),
|
|
164
164
|
projectGraphConflicts: graphConflicts.length || undefined,
|
|
165
|
-
outputProjectGraphConflicts: outputGraphConflicts.length || undefined,
|
|
165
|
+
outputProjectGraphConflicts: outputGraphConflicts.length || undefined, projectGraphCssModuleUseSiteConflicts: graphConflicts.filter((conflict) => conflict.gateId === 'project-css-module-use-site-graph').length || undefined,
|
|
166
166
|
projectGraphDeltaConflicts: deltaGraphConflicts.length || undefined,
|
|
167
167
|
projectGraphSourceSpanConflicts: deltaGraphConflicts.filter((conflict) => conflict.code === 'project-source-span-delta-conflict').length || undefined,
|
|
168
168
|
projectGraphCompilerTypeConflicts: deltaGraphConflicts.filter((conflict) => conflict.code === 'project-public-compiler-type-delta-conflict').length || undefined,
|
package/package.json
CHANGED