@shapeshift-labs/frontier-lang-compiler 0.2.162 → 0.2.164
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/internal/index-impl/moduleHostResourceImportMetadata.js +47 -0
- package/dist/internal/index-impl/projectSymbolGraphCompilerAdvancedTypeMetadata.js +84 -12
- package/dist/internal/index-impl/projectSymbolGraphCompilerFacts.js +1 -1
- package/dist/internal/index-impl/projectSymbolGraphCssModules.js +48 -4
- package/dist/internal/index-impl/projectSymbolGraphJsxPropRecordFields.js +91 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxPropValues.js +26 -135
- package/dist/internal/index-impl/projectSymbolGraphJsxRecords.js +4 -31
- package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturnCollectionHelpers.js +201 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturnCollections.js +210 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturns.js +12 -5
- package/dist/internal/index-impl/projectSymbolGraphJsxSpreadPropValues.js +196 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxStaticLiterals.js +207 -0
- package/dist/internal/index-impl/projectSymbolGraphModuleResolution.js +12 -14
- package/dist/internal/index-impl/projectSymbolGraphPackageConditions.js +22 -17
- package/dist/internal/index-impl/syntaxModuleDeclarationEntries.js +27 -1
- package/dist/js-ts-safe-project-merge-html-css-matrix.js +7 -2
- package/dist/js-ts-safe-project-merge-html-css-summary.js +90 -8
- package/dist/js-ts-safe-project-merge-html-css.js +137 -3
- package/dist/js-ts-safe-project-merge-jsx-graph-conflict-details.js +9 -0
- package/dist/js-ts-safe-project-merge-missing-evidence.js +12 -12
- package/dist/js-ts-safe-project-merge-source-text-candidate.js +68 -0
- package/dist/js-ts-safe-project-merge-summary.js +8 -11
- package/dist/js-ts-safe-project-merge.js +3 -0
- package/package.json +1 -1
|
@@ -7,11 +7,13 @@ function htmlCssProjectSummary(files) {
|
|
|
7
7
|
htmlParserEvidenceFiles: htmlFiles.filter(hasHtmlParserEvidence).length, cssParserEvidenceFiles: cssFiles.filter(hasCssParserEvidence).length, htmlCssParserEvidenceFiles: htmlCssFiles.filter((file) => hasHtmlParserEvidence(file) || hasCssParserEvidence(file)).length,
|
|
8
8
|
htmlParserEvidenceFailedFiles: htmlFiles.filter(hasParserEvidenceFailure).length, cssParserEvidenceFailedFiles: cssFiles.filter(hasParserEvidenceFailure).length, htmlCssParserEvidenceFailedFiles: htmlCssFiles.filter(hasParserEvidenceFailure).length,
|
|
9
9
|
htmlIdentityEvidenceFiles: htmlFiles.filter(hasHtmlIdentityEvidence).length, cssSelectorTargetEvidenceFiles: cssFiles.filter(hasCssSelectorTargetEvidence).length, htmlCssStructuralTargetEvidenceFiles: htmlCssFiles.filter((file) => hasHtmlIdentityEvidence(file) || hasCssSelectorTargetEvidence(file)).length,
|
|
10
|
-
|
|
10
|
+
cssSelectorTargetGraphEvidenceFiles: cssFiles.filter(hasCssSelectorTargetGraphEvidence).length, cssSelectorSpecificityEvidenceFiles: cssFiles.filter(hasCssSelectorSpecificityEvidence).length, cssSelectorTargetMoveFiles: cssFiles.filter(hasCssSelectorTargetMove).length,
|
|
11
|
+
htmlExplicitIdentityEvidenceFiles: htmlFiles.filter(hasHtmlExplicitIdentityEvidence).length, htmlPathOnlyIdentityResidualFiles: htmlFiles.filter(hasHtmlPathOnlyIdentityResidual).length, htmlDuplicateIdentityEvidenceFiles: htmlFiles.filter(hasHtmlDuplicateIdentityEvidence).length, htmlDuplicateIdentityKeys: htmlFiles.reduce((sum, file) => sum + htmlDuplicateIdentityKeyCount(file), 0),
|
|
11
12
|
htmlRuntimeBoundaryEvidenceFiles: htmlFiles.filter(hasHtmlRuntimeBoundaryEvidence).length, htmlFrameworkBoundaryEvidenceFiles: htmlFiles.filter(hasHtmlFrameworkBoundaryEvidence).length, htmlProofGapBlockedFiles: htmlFiles.filter(hasHtmlProofGapBlockedConflict).length,
|
|
12
13
|
htmlIdentityEvidenceFailedFiles: htmlFiles.filter(hasHtmlIdentityEvidenceFailure).length, cssSelectorTargetConflictFiles: cssFiles.filter(hasCssSelectorTargetConflict).length, htmlCssStructuralTargetEvidenceFailedFiles: htmlCssFiles.filter((file) => hasHtmlIdentityEvidenceFailure(file) || hasCssSelectorTargetConflict(file)).length,
|
|
13
14
|
cssSelectorTargetRebasedFiles: cssFiles.filter(hasCssSelectorTargetRebase).length,
|
|
14
15
|
cssScopedCascadeFiles: cssFiles.filter(hasCssScopedCascadeScope).length, cssScopedCascadeEvidenceFiles: cssFiles.filter(hasCssScopedCascadeEvidence).length, cssScopedCascadeBlockedFiles: cssFiles.filter(hasCssScopedCascadeMissingProof).length,
|
|
16
|
+
cssDependencySurfaceFiles: cssFiles.filter(hasCssDependencySurface).length, cssDependencyGraphEvidenceFiles: cssFiles.filter((file) => hasCssDependencySurface(file) && hasCssDependencyGraphEvidence(file)).length, cssDependencyGraphMissingProofFiles: cssFiles.filter(hasCssDependencyGraphMissingProof).length, cssDependencyGraphBlockedFiles: cssFiles.filter(hasCssDependencyGraphBlockedConflict).length,
|
|
15
17
|
htmlCssBrowserRuntimeProofs: htmlCssFiles.filter(hasBrowserRuntimeProof).length
|
|
16
18
|
};
|
|
17
19
|
}
|
|
@@ -32,46 +34,126 @@ function hasCssParserEvidence(file) {
|
|
|
32
34
|
function hasParserEvidenceFailure(file) { return (file?.result?.parserEvidence?.parseErrors ?? 0) > 0; }
|
|
33
35
|
function hasHtmlIdentityEvidence(file) {
|
|
34
36
|
const evidence = file?.result?.identityEvidence;
|
|
35
|
-
return evidence?.parserBackedStructuralSpans === true && evidence.structuralAddressability === true;
|
|
37
|
+
return evidence?.parserBackedStructuralSpans === true && evidence.structuralAddressability === true && !hasDuplicateExplicitIdentityKeys(evidence);
|
|
36
38
|
}
|
|
37
39
|
function hasHtmlExplicitIdentityEvidence(file) {
|
|
38
40
|
const evidence = file?.result?.identityEvidence;
|
|
39
41
|
return hasHtmlIdentityEvidence(file) && evidence.explicitIdentityAvailable === true;
|
|
40
42
|
}
|
|
41
43
|
function hasHtmlPathOnlyIdentityResidual(file) { return (file?.result?.identityEvidence?.pathOnlyIdentityElements ?? 0) > 0; }
|
|
42
|
-
function hasHtmlRuntimeBoundaryEvidence(file) {
|
|
43
|
-
|
|
44
|
+
function hasHtmlRuntimeBoundaryEvidence(file) {
|
|
45
|
+
return (file?.result?.identityEvidence?.runtimeBoundaryElements ?? 0) > 0 || hasRuntimeBoundaryConflict(file);
|
|
46
|
+
}
|
|
47
|
+
function hasHtmlFrameworkBoundaryEvidence(file) {
|
|
48
|
+
return (file?.result?.identityEvidence?.frameworkBoundaryElements ?? 0) > 0 || hasFrameworkBoundaryConflict(file);
|
|
49
|
+
}
|
|
44
50
|
function hasHtmlIdentityEvidenceFailure(file) {
|
|
45
51
|
const evidence = file?.result?.identityEvidence;
|
|
46
|
-
return Boolean(evidence) && (evidence.parserBackedStructuralSpans !== true || evidence.structuralAddressability !== true);
|
|
52
|
+
return Boolean(evidence) && (evidence.parserBackedStructuralSpans !== true || evidence.structuralAddressability !== true || hasDuplicateExplicitIdentityKeys(evidence));
|
|
47
53
|
}
|
|
48
54
|
function hasCssSelectorTargetEvidence(file) {
|
|
49
55
|
const evidence = file?.result?.selectorTargetEvidence;
|
|
50
56
|
return evidence?.parserBackedRuleSpans === true;
|
|
51
57
|
}
|
|
58
|
+
function hasCssSelectorTargetGraphEvidence(file) {
|
|
59
|
+
return file?.result?.selectorTargetEvidence?.selectorTargetGraphHashPresent === true;
|
|
60
|
+
}
|
|
61
|
+
function hasCssSelectorSpecificityEvidence(file) {
|
|
62
|
+
const sides = Object.values(file?.result?.selectorTargetEvidence?.sides ?? {});
|
|
63
|
+
return sides.length > 0 && sides.every((side) => (side?.ruleCount ?? 0) === 0 || (side?.selectorSpecificityRecords ?? 0) >= side.ruleCount);
|
|
64
|
+
}
|
|
65
|
+
function hasCssSelectorTargetMove(file) {
|
|
66
|
+
return (file?.result?.selectorTargetEvidence?.selectorMoveCount ?? 0) > 0;
|
|
67
|
+
}
|
|
52
68
|
function hasCssSelectorTargetConflict(file) {
|
|
53
69
|
return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => conflict.code === 'css-selector-target-conflict');
|
|
54
70
|
}
|
|
55
71
|
function hasHtmlProofGapBlockedConflict(file) {
|
|
56
72
|
return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => conflict.code === 'html-proof-gap-blocked');
|
|
57
73
|
}
|
|
74
|
+
function hasRuntimeBoundaryConflict(file) {
|
|
75
|
+
return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => HtmlRuntimeBoundaryReasonCodes.has(conflict?.details?.reasonCode));
|
|
76
|
+
}
|
|
77
|
+
function hasFrameworkBoundaryConflict(file) {
|
|
78
|
+
return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => HtmlFrameworkBoundaryReasonCodes.has(conflict?.details?.reasonCode));
|
|
79
|
+
}
|
|
58
80
|
function hasCssSelectorTargetRebase(file) { return (file?.result?.selectorTargetEvidence?.rebasedChangeCount ?? 0) > 0; }
|
|
59
|
-
function hasCssScopedCascadeScope(file) {
|
|
81
|
+
function hasCssScopedCascadeScope(file) {
|
|
82
|
+
return cssScopedRuleCount(file) > 0 || hasCssScopedCascadeProofReason(file) || file?.result?.parserEvidence?.scopedCascadeGraphHashPresent === false;
|
|
83
|
+
}
|
|
60
84
|
function hasCssScopedCascadeEvidence(file) {
|
|
61
|
-
return hasCssScopedCascadeScope(file) && file?.result?.parserEvidence?.scopedCascadeGraphHashPresent === true;
|
|
85
|
+
return hasCssScopedCascadeScope(file) && !hasCssScopedCascadeMissingProof(file) && file?.result?.parserEvidence?.scopedCascadeGraphHashPresent === true;
|
|
62
86
|
}
|
|
63
87
|
function hasCssScopedCascadeMissingProof(file) {
|
|
64
|
-
return
|
|
88
|
+
return hasCssScopedCascadeProofReason(file);
|
|
89
|
+
}
|
|
90
|
+
function hasCssScopedCascadeProofReason(file) {
|
|
91
|
+
return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => ScopedCascadeMissingProofReasonCodes.has(conflict?.details?.reasonCode));
|
|
65
92
|
}
|
|
66
93
|
function cssScopedRuleCount(file) {
|
|
67
94
|
const sides = Object.values(file?.result?.selectorTargetEvidence?.sides ?? {});
|
|
68
95
|
return sides.reduce((count, side) => Math.max(count, side?.scopedRuleCount ?? 0), 0);
|
|
69
96
|
}
|
|
97
|
+
function hasCssDependencySurface(file) {
|
|
98
|
+
return hasCssDependencyEvidenceSurface(file) || hasCssDependencyTextSurface(file) || hasCssDependencyConflictSurface(file);
|
|
99
|
+
}
|
|
100
|
+
function hasCssDependencyGraphEvidence(file) {
|
|
101
|
+
return cssDependencyEvidenceRecords(file).some((evidence) => evidence.dependencyGraphHashPresent === true || evidence.cssDependencyGraphHashPresent === true || typeof evidence.dependencyGraphHash === 'string' || typeof evidence.cssDependencyGraphHash === 'string' || typeof evidence.graphHash === 'string' || typeof evidence.customPropertyGraphHash === 'string' || typeof evidence.animationGraphHash === 'string' || typeof evidence.fontFaceGraphHash === 'string' || typeof evidence.assetGraphHash === 'string');
|
|
102
|
+
}
|
|
103
|
+
function hasCssDependencyGraphMissingProof(file) { return hasCssDependencySurface(file) && !hasCssDependencyGraphEvidence(file); }
|
|
104
|
+
function hasCssDependencyEvidenceSurface(file) {
|
|
105
|
+
return cssDependencyEvidenceRecords(file).some((evidence) => evidence.hasDependencySurface === true || (evidence.dependencySurfaceCount ?? 0) > 0 || (evidence.customPropertyDefinitions ?? 0) > 0 || (evidence.customPropertyReferences ?? 0) > 0 || (evidence.varReferences ?? 0) > 0 || (evidence.varFallbackReferences ?? 0) > 0 || (evidence.animationNameLinks ?? 0) > 0 || (evidence.keyframeLinks ?? 0) > 0 || (evidence.fontFaceLinks ?? 0) > 0 || (evidence.urlAssetReferences ?? 0) > 0);
|
|
106
|
+
}
|
|
107
|
+
function hasCssDependencyTextSurface(file) {
|
|
108
|
+
const sourceText = cssDependencySourceText(file);
|
|
109
|
+
return sourceText.length > 0 && CssDependencySurfacePatterns.some((pattern) => pattern.test(sourceText));
|
|
110
|
+
}
|
|
111
|
+
function hasCssDependencyConflictSurface(file) {
|
|
112
|
+
return cssFileConflicts(file).some(isCssDependencyConflict);
|
|
113
|
+
}
|
|
114
|
+
function hasCssDependencyGraphBlockedConflict(file) {
|
|
115
|
+
return cssFileConflicts(file).some((conflict) => isCssDependencyConflict(conflict) || CssDependencyMissingProofReasonCodes.has(conflict?.details?.reasonCode));
|
|
116
|
+
}
|
|
117
|
+
function cssDependencyEvidenceRecords(file) {
|
|
118
|
+
const result = file?.result ?? {};
|
|
119
|
+
return [result.dependencyEvidence, result.cssDependencyEvidence, result.dependencyGraphEvidence, result.cssDependencyGraphEvidence, result.parserEvidence?.dependencyEvidence, result.parserEvidence?.cssDependencyEvidence, result.parserEvidence?.dependencyGraphEvidence, result.parserEvidence?.cssDependencyGraphEvidence].filter(isPlainObject);
|
|
120
|
+
}
|
|
121
|
+
function cssDependencySourceText(file) {
|
|
122
|
+
return [file?.outputSourceText, file?.sourceText, file?.result?.mergedSourceText].filter((value) => typeof value === 'string').join('\n');
|
|
123
|
+
}
|
|
124
|
+
function cssFileConflicts(file) { return file?.result?.conflicts ?? file?.conflicts ?? []; }
|
|
125
|
+
function isCssDependencyConflict(conflict) {
|
|
126
|
+
const details = conflict?.details ?? {};
|
|
127
|
+
const codes = [conflict?.code, details.reasonCode, details.proofGap?.code].map((value) => String(value ?? ''));
|
|
128
|
+
return codes.some((code) => CssDependencyCodeFragments.some((fragment) => code.includes(fragment))) || isCssDependencyAtRule(details.before) || isCssDependencyAtRule(details.after);
|
|
129
|
+
}
|
|
130
|
+
function isCssDependencyAtRule(shape) { return CssDependencyAtRuleNames.has(String(shape?.atRuleName ?? '').toLowerCase()); }
|
|
70
131
|
function hasBrowserRuntimeProof(file) {
|
|
71
132
|
const admission = file?.result?.admission ?? file?.admission ?? {};
|
|
72
133
|
return admission.browserRuntimeEquivalenceClaim === true || admission.browserCascadeEquivalenceClaim === true || admission.browserRenderEquivalenceClaim === true;
|
|
73
134
|
}
|
|
135
|
+
function hasHtmlDuplicateIdentityEvidence(file) { return hasDuplicateExplicitIdentityKeys(file?.result?.identityEvidence); }
|
|
136
|
+
function htmlDuplicateIdentityKeyCount(file) {
|
|
137
|
+
return duplicateExplicitIdentityKeys(file?.result?.identityEvidence).length;
|
|
138
|
+
}
|
|
139
|
+
function hasDuplicateExplicitIdentityKeys(evidence) {
|
|
140
|
+
return duplicateExplicitIdentityKeys(evidence).length > 0;
|
|
141
|
+
}
|
|
142
|
+
function duplicateExplicitIdentityKeys(evidence) {
|
|
143
|
+
return Object.values(evidence?.sides ?? {}).flatMap((side) => {
|
|
144
|
+
const counts = new Map();
|
|
145
|
+
for (const key of side?.explicitIdentityKeys ?? []) counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
146
|
+
return [...counts.entries()].filter(([, count]) => count > 1).map(([key]) => key);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
74
149
|
|
|
75
150
|
const ScopedCascadeMissingProofReasonCodes = new Set(['css-scoped-cascade-equivalence-unproved', 'css-media-cascade-scope-unproved', 'css-supports-cascade-scope-unproved', 'css-container-cascade-scope-unproved', 'css-layer-cascade-scope-unproved', 'css-scope-cascade-scope-unproved']);
|
|
151
|
+
const HtmlRuntimeBoundaryReasonCodes = new Set(['script-runtime-boundary', 'style-runtime-boundary', 'template-runtime-boundary', 'slot-runtime-boundary', 'custom-element-runtime-boundary', 'event-handler-runtime-boundary', 'inline-style-runtime-boundary', 'iframe-runtime-boundary', 'iframe-srcdoc-runtime-boundary']);
|
|
152
|
+
const HtmlFrameworkBoundaryReasonCodes = new Set(['framework-directive-boundary', 'custom-element-runtime-boundary']);
|
|
153
|
+
const CssDependencyMissingProofReasonCodes = new Set(['css-dependency-graph-evidence-missing', 'css-custom-property-dependency-graph-unproved', 'css-var-fallback-dependency-graph-unproved', 'css-animation-name-keyframes-graph-unproved', 'css-font-face-dependency-graph-unproved', 'css-url-asset-dependency-graph-unproved']);
|
|
154
|
+
const CssDependencyAtRuleNames = new Set(['keyframes', 'font-face']);
|
|
155
|
+
const CssDependencyCodeFragments = ['custom-property', 'var-fallback', 'variable-dependency', 'dependency-graph', 'keyframes', 'animation-name', 'font-face', 'url-asset', 'asset-dependency'];
|
|
156
|
+
const CssDependencySurfacePatterns = [/(^|[;{\s])--[-_A-Za-z][\w-]*\s*:/, /\bvar\s*\(/i, /@(?:-[\w]+-)?keyframes\b/i, /(^|[;{\s])animation(?:-name)?\s*:/i, /@font-face\b/i, /\burl\s*\(/i];
|
|
157
|
+
function isPlainObject(value) { return Boolean(value && typeof value === 'object' && !Array.isArray(value)); }
|
|
76
158
|
|
|
77
159
|
export { htmlCssProjectSummary };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { safeMergeCssSource } from '@shapeshift-labs/frontier-lang-css';
|
|
2
2
|
import { safeMergeHtmlSource } from '@shapeshift-labs/frontier-lang-html';
|
|
3
3
|
import { compactRecord } from './js-ts-safe-merge-context.js';
|
|
4
|
-
import { hashText, safeId } from './js-ts-safe-project-merge-core.js';
|
|
4
|
+
import { hashText, safeId, uniqueStrings } from './js-ts-safe-project-merge-core.js';
|
|
5
5
|
|
|
6
6
|
function projectFileLanguage(file, input) {
|
|
7
7
|
return file.language ?? inferLanguageFromPath(file.sourcePath) ?? input.language ?? 'typescript';
|
|
@@ -12,8 +12,12 @@ function maybeMergeHtmlCssProjectFile(options) {
|
|
|
12
12
|
const language = String(context.language ?? '').toLowerCase();
|
|
13
13
|
const merge = language === 'html' ? safeMergeHtmlSource : language === 'css' ? safeMergeCssSource : undefined;
|
|
14
14
|
if (!merge) return undefined;
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
const resultId = `${projectId}_${safeId(file.sourcePath)}`;
|
|
16
|
+
const result = merge({ ...sourceInput, ...htmlCssMergeOptionsForProjectFile(input, file.sourcePath, language), ...context, id: resultId, baseSourceText: base, workerSourceText: worker, headSourceText: head });
|
|
17
|
+
const admittedResult = language === 'html' && result.status === 'merged'
|
|
18
|
+
? blockHtmlProofGapChanges({ result, id: resultId, sourcePath: file.sourcePath, base, worker, head }) ?? result
|
|
19
|
+
: result;
|
|
20
|
+
return admittedResult.status === 'merged' ? mergedHtmlCssFile(file, context, admittedResult, language) : blockedHtmlCssFile(file, context, admittedResult);
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
function inferLanguageFromPath(sourcePath) {
|
|
@@ -32,6 +36,136 @@ function htmlCssMergeOptionsForProjectFile(input, sourcePath, language) {
|
|
|
32
36
|
return compactRecord({ ...(language === 'css' ? input.cssMergeOptions ?? input.styleMergeOptions : input.htmlMergeOptions ?? input.markupMergeOptions), ...(byPath?.[sourcePath] ?? {}) });
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
function blockHtmlProofGapChanges({ result, id, sourcePath, base, worker, head }) {
|
|
40
|
+
const conflicts = [
|
|
41
|
+
htmlDuplicateIdentityConflict(result),
|
|
42
|
+
...htmlRuntimeBoundaryChanges(base, worker, head).map((change) => htmlProofGapConflict(id, sourcePath, change.reasonCode, change))
|
|
43
|
+
].filter(Boolean);
|
|
44
|
+
if (!conflicts.length) return undefined;
|
|
45
|
+
const allConflicts = [...(result.conflicts ?? []), ...conflicts];
|
|
46
|
+
const { mergedSourceText, mergedSourceHash, ...rest } = result;
|
|
47
|
+
return compactRecord({
|
|
48
|
+
...rest,
|
|
49
|
+
status: 'blocked',
|
|
50
|
+
operation: 'blocked',
|
|
51
|
+
conflicts: allConflicts,
|
|
52
|
+
admission: blockedHtmlProofGapAdmission(result.admission, allConflicts),
|
|
53
|
+
autoMergeClaim: false,
|
|
54
|
+
semanticEquivalenceClaim: false,
|
|
55
|
+
browserRuntimeEquivalenceClaim: false
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function htmlDuplicateIdentityConflict(result) {
|
|
60
|
+
const duplicates = duplicateHtmlExplicitIdentityKeys(result?.identityEvidence);
|
|
61
|
+
if (!duplicates.length) return undefined;
|
|
62
|
+
return htmlProofGapConflict(result.id, result.sourcePath, 'html-duplicate-explicit-identity', {
|
|
63
|
+
boundary: 'html-explicit-identity',
|
|
64
|
+
duplicateIdentityKeys: duplicates
|
|
65
|
+
}, 'html-duplicate-identity-blocked');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function duplicateHtmlExplicitIdentityKeys(identityEvidence) {
|
|
69
|
+
return Object.entries(identityEvidence?.sides ?? {}).flatMap(([side, evidence]) => {
|
|
70
|
+
const counts = new Map();
|
|
71
|
+
for (const key of evidence?.explicitIdentityKeys ?? []) counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
72
|
+
return [...counts.entries()]
|
|
73
|
+
.filter(([, count]) => count > 1)
|
|
74
|
+
.map(([key, count]) => ({ side, key, count }));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function htmlRuntimeBoundaryChanges(base, worker, head) {
|
|
79
|
+
const baseEventHandlers = htmlEventHandlerBoundaryFingerprint(base);
|
|
80
|
+
return [
|
|
81
|
+
htmlRuntimeBoundaryChange('worker', base, worker, baseEventHandlers),
|
|
82
|
+
htmlRuntimeBoundaryChange('head', base, head, baseEventHandlers)
|
|
83
|
+
].filter(Boolean);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function htmlRuntimeBoundaryChange(side, base, sourceText, baseEventHandlers) {
|
|
87
|
+
if (sourceText === base) return undefined;
|
|
88
|
+
const eventHandlers = htmlEventHandlerBoundaryFingerprint(sourceText);
|
|
89
|
+
if (eventHandlers === baseEventHandlers) return undefined;
|
|
90
|
+
return {
|
|
91
|
+
side,
|
|
92
|
+
reasonCode: 'event-handler-runtime-boundary',
|
|
93
|
+
boundary: 'html-event-handler-attribute',
|
|
94
|
+
boundaryAttributes: htmlEventHandlerBoundaryAttributeNames(sourceText)
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function htmlEventHandlerBoundaryFingerprint(sourceText) {
|
|
99
|
+
return htmlEventHandlerBoundaryAttributes(sourceText)
|
|
100
|
+
.map((attribute) => `${attribute.tagName}:${attribute.name}=${String(attribute.value)}`)
|
|
101
|
+
.sort()
|
|
102
|
+
.join('\n');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function htmlEventHandlerBoundaryAttributeNames(sourceText) {
|
|
106
|
+
return uniqueStrings(htmlEventHandlerBoundaryAttributes(sourceText).map((attribute) => attribute.name));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function htmlEventHandlerBoundaryAttributes(sourceText) {
|
|
110
|
+
const attributes = [];
|
|
111
|
+
for (const tag of String(sourceText ?? '').matchAll(/<[A-Za-z][\w:-]*(?:\s+[^<>]*?)?\/?>/g)) {
|
|
112
|
+
const parsed = /^<([A-Za-z][\w:-]*)([\s\S]*?)\/?>$/.exec(tag[0]);
|
|
113
|
+
if (!parsed) continue;
|
|
114
|
+
const tagName = parsed[1].toLowerCase();
|
|
115
|
+
for (const attribute of parseHtmlAttributes(parsed[2] ?? '')) {
|
|
116
|
+
if (/^on[\w:.-]+$/i.test(attribute.name)) attributes.push({ ...attribute, name: attribute.name.toLowerCase(), tagName });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return attributes;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function parseHtmlAttributes(text) {
|
|
123
|
+
const attributes = [];
|
|
124
|
+
const pattern = /([:@A-Za-z_][\w:.-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
125
|
+
for (const match of text.matchAll(pattern)) attributes.push({ name: match[1], value: match[2] ?? match[3] ?? match[4] ?? true });
|
|
126
|
+
return attributes;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function htmlProofGapConflict(id, sourcePath, reasonCode, details = {}, code = 'html-proof-gap-blocked') {
|
|
130
|
+
return {
|
|
131
|
+
code,
|
|
132
|
+
gateId: 'html-semantic-merge',
|
|
133
|
+
sourcePath,
|
|
134
|
+
details: compactRecord({
|
|
135
|
+
reasonCode,
|
|
136
|
+
conflictKey: `html#${id}#${reasonCode}#${details.side ?? details.duplicateIdentityKeys?.[0]?.key ?? sourcePath ?? 'source'}`,
|
|
137
|
+
proofGap: {
|
|
138
|
+
code: reasonCode,
|
|
139
|
+
status: 'not-claimed',
|
|
140
|
+
summary: htmlProofGapSummary(reasonCode),
|
|
141
|
+
failClosed: true,
|
|
142
|
+
semanticEquivalenceClaim: false
|
|
143
|
+
},
|
|
144
|
+
...details
|
|
145
|
+
})
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function htmlProofGapSummary(reasonCode) {
|
|
150
|
+
if (reasonCode === 'html-duplicate-explicit-identity') return 'Duplicate explicit HTML identity keys make structural target admission ambiguous.';
|
|
151
|
+
if (reasonCode === 'event-handler-runtime-boundary') return 'HTML event handler attributes execute in the browser runtime and require source-bound host evidence.';
|
|
152
|
+
return 'HTML proof gap requires source-bound evidence before structural merge admission.';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function blockedHtmlProofGapAdmission(admission = {}, conflicts = []) {
|
|
156
|
+
return {
|
|
157
|
+
...admission,
|
|
158
|
+
status: 'blocked',
|
|
159
|
+
action: 'human-review',
|
|
160
|
+
reviewRequired: true,
|
|
161
|
+
autoApplyCandidate: false,
|
|
162
|
+
autoMergeClaim: false,
|
|
163
|
+
semanticEquivalenceClaim: false,
|
|
164
|
+
browserRuntimeEquivalenceClaim: false,
|
|
165
|
+
reasonCodes: uniqueStrings([...(admission.reasonCodes ?? []), ...conflicts.map((conflict) => conflict.details?.reasonCode ?? conflict.code)])
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
35
169
|
function mergedHtmlCssFile(file, context, result, language) {
|
|
36
170
|
return compactRecord({
|
|
37
171
|
kind: 'frontier.lang.jsTsProjectSafeMergeFile', version: 1, sourcePath: file.sourcePath, language: context.language, status: 'merged', operation: `merged-${language}-source`,
|
|
@@ -98,6 +98,15 @@ function jsxPropDetails(record) {
|
|
|
98
98
|
propValueReferenceRoot: record.propValueReferenceRoot, propValueReferencePath: record.propValueReferencePath,
|
|
99
99
|
propValueOptionalReference: record.propValueOptionalReference, propValueOptionalReferenceSegments: record.propValueOptionalReferenceSegments,
|
|
100
100
|
propValueOptionalReferenceSegmentIndexes: record.propValueOptionalReferenceSegmentIndexes, propValueOptionalNullishBoundaryCount: record.propValueOptionalNullishBoundaryCount,
|
|
101
|
+
propValueClaimScope: record.propValueClaimScope, propValueRenderEquivalenceClaim: record.propValueRenderEquivalenceClaim,
|
|
102
|
+
propValueStaticSpreadSourceKind: record.propValueStaticSpreadSourceKind, propValueStaticSpreadSourceName: record.propValueStaticSpreadSourceName,
|
|
103
|
+
propValueStaticSpreadPropEntries: record.propValueStaticSpreadPropEntries, propValueStaticSpreadPropNames: record.propValueStaticSpreadPropNames,
|
|
104
|
+
propValueStaticSpreadPropCount: record.propValueStaticSpreadPropCount,
|
|
105
|
+
propValueStaticSpreadEffectivePropEntries: record.propValueStaticSpreadEffectivePropEntries, propValueStaticSpreadEffectivePropNames: record.propValueStaticSpreadEffectivePropNames,
|
|
106
|
+
propValueStaticSpreadExplicitOverridePropNames: record.propValueStaticSpreadExplicitOverridePropNames,
|
|
107
|
+
propValueStaticSpreadOverridesExplicitPropNames: record.propValueStaticSpreadOverridesExplicitPropNames,
|
|
108
|
+
propValueStaticSpreadDuplicatePropNames: record.propValueStaticSpreadDuplicatePropNames,
|
|
109
|
+
propValueStaticSpreadPrecedenceStatus: record.propValueStaticSpreadPrecedenceStatus,
|
|
101
110
|
propValueDynamicText: record.propValueDynamicText, propValueDynamicBlockerReasonCode: record.propValueDynamicBlockerReasonCode,
|
|
102
111
|
propValueExpressionHash: record.propValueExpressionHash, propValueSignatureHash: record.propValueSignatureHash,
|
|
103
112
|
componentPropRenderFlowStatus: record.componentPropRenderFlowStatus, componentPropRenderFlowReasonCode: record.componentPropRenderFlowReasonCode,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { HtmlCssProjectMergeMissingSignals, htmlCssProjectMergeAdmissionMatrixRows, htmlCssProjectMergeMatrixProofStatus, htmlCssProjectMergeMissingEvidenceItems, htmlCssProjectMergeMissingEvidenceRoutes } from './js-ts-safe-project-merge-html-css-matrix.js';
|
|
2
|
+
import { sourceTextMergeMatrixProofStatus, sourceTextMergeMissingEvidenceItem } from './js-ts-safe-project-merge-source-text-candidate.js';
|
|
2
3
|
const ProjectMergeMissingSignals = Object.freeze({
|
|
4
|
+
sourceTextMergeCandidate: 'source-text-merge-candidate-not-produced',
|
|
3
5
|
outputDiagnosticsGate: 'output-diagnostics-gate-not-run',
|
|
4
6
|
declarationGate: 'declaration-gate-not-run',
|
|
5
7
|
qualityGates: 'quality-gates-not-run',
|
|
@@ -17,6 +19,7 @@ const ProjectMergeMissingSignals = Object.freeze({
|
|
|
17
19
|
});
|
|
18
20
|
|
|
19
21
|
const ProjectMergeMissingEvidenceRoutes = Object.freeze({
|
|
22
|
+
[ProjectMergeMissingSignals.sourceTextMergeCandidate]: route('produce-source-text-merge-candidate', 'source-files', 'run-conservative-three-way-source-merge'),
|
|
20
23
|
[ProjectMergeMissingSignals.outputDiagnosticsGate]: route('run-output-diagnostics', 'project-output', 'supply-output-diagnostics'),
|
|
21
24
|
[ProjectMergeMissingSignals.declarationGate]: route('emit-output-declarations', 'project-output', 'supply-declaration-output'),
|
|
22
25
|
[ProjectMergeMissingSignals.qualityGates]: route('attach-quality-gates', 'quality-gates', 'attach-passing-quality-gates'),
|
|
@@ -34,6 +37,7 @@ const ProjectMergeMissingEvidenceRoutes = Object.freeze({
|
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
const ProjectMergeAdmissionMatrixRows = Object.freeze([
|
|
40
|
+
matrixRow('source-text-merge-candidate', 'baseline', ['source-text-merge-candidate'], [ProjectMergeMissingSignals.sourceTextMergeCandidate]),
|
|
37
41
|
matrixRow('parser-source-span-trivia', 'partial', ['source-span-roundtrip'], [ProjectMergeMissingSignals.sourceSpanRoundtrip, ProjectMergeMissingSignals.semanticArtifacts]),
|
|
38
42
|
matrixRow('scope-use-def-graph', 'partial', ['project-graph-delta'], [ProjectMergeMissingSignals.projectGraphEvidence, ProjectMergeMissingSignals.projectGraphDeltaEvidence]),
|
|
39
43
|
matrixRow('module-export-import-graph', 'partial', ['project-graph-delta'], [ProjectMergeMissingSignals.projectGraphEvidence, ProjectMergeMissingSignals.projectGraphDeltaEvidence]),
|
|
@@ -54,6 +58,8 @@ const ProjectMergeAdmissionMatrixRows = Object.freeze([
|
|
|
54
58
|
|
|
55
59
|
function missingEvidenceItems(summary, context = {}) {
|
|
56
60
|
const items = [];
|
|
61
|
+
const sourceTextMissing = sourceTextMergeMissingEvidenceItem(summary, ProjectMergeMissingSignals.sourceTextMergeCandidate, missingEvidenceItem);
|
|
62
|
+
if (sourceTextMissing) items.push(sourceTextMissing);
|
|
57
63
|
if (!context.hasProjectGraphEvidence) items.push(missingEvidenceItem({
|
|
58
64
|
code: ProjectMergeMissingSignals.projectGraphEvidence,
|
|
59
65
|
scope: 'project-graph',
|
|
@@ -254,6 +260,8 @@ function matrixProofStatus(level, summary, proofEvidence) {
|
|
|
254
260
|
if (levelStatuses[level]) return levelStatuses[level];
|
|
255
261
|
const htmlCssStatus = htmlCssProjectMergeMatrixProofStatus(level, summary);
|
|
256
262
|
if (htmlCssStatus) return htmlCssStatus;
|
|
263
|
+
const sourceTextStatus = sourceTextMergeMatrixProofStatus(level, summary);
|
|
264
|
+
if (sourceTextStatus) return sourceTextStatus;
|
|
257
265
|
if (level === 'project-graph-delta') return summary.projectGraphDeltaEvidenceIncluded ? (summary.projectGraphDeltaConflicts ? 'failed' : 'passed') : 'missing';
|
|
258
266
|
if (level === 'project-graph-evidence') return summary.projectGraphConflicts ? 'failed' : summary.projectGraphEvidenceIncluded || summary.projectGraphDeltaEvidenceIncluded ? 'passed' : 'missing';
|
|
259
267
|
if (level === 'css-module-use-site-graph') return summary.projectGraphCssModuleUseSiteConflicts ? 'failed' : summary.projectGraphCssModuleUseSiteGraphs ? 'passed' : summary.projectGraphEvidenceIncluded ? 'absent' : 'missing';
|
|
@@ -292,12 +300,10 @@ function countField(items, field) {
|
|
|
292
300
|
|
|
293
301
|
function countRoute(items, field = 'id') {
|
|
294
302
|
const counts = {};
|
|
295
|
-
for (const item of items)
|
|
296
|
-
const key = field === 'lane' ? item?.routeLane ?? item?.route?.lane : item?.routeId ?? item?.route?.id;
|
|
297
|
-
if (key) counts[key] = (counts[key] ?? 0) + 1;
|
|
298
|
-
}
|
|
303
|
+
for (const item of items) countRouteItem(counts, item, field);
|
|
299
304
|
return counts;
|
|
300
305
|
}
|
|
306
|
+
function countRouteItem(counts, item, field) { const key = field === 'lane' ? item?.routeLane ?? item?.route?.lane : item?.routeId ?? item?.route?.id; if (key) counts[key] = (counts[key] ?? 0) + 1; }
|
|
301
307
|
|
|
302
308
|
function route(id, lane, next) { return Object.freeze({ id, lane, next }); }
|
|
303
309
|
function shouldRecommendRerun(missingEvidence = [], options = {}) {
|
|
@@ -307,13 +313,7 @@ function shouldRecommendRerun(missingEvidence = [], options = {}) {
|
|
|
307
313
|
if (reasonCodes.length) return reasonCodes.every((code) => rerunReasonCodes.has(code));
|
|
308
314
|
return missingEvidence[0]?.action === 'rerun-gate' && missingEvidence[0]?.kind === 'quality-gate';
|
|
309
315
|
}
|
|
310
|
-
function isSemanticEquivalenceMissing(item) {
|
|
311
|
-
|
|
312
|
-
|| item?.code === ProjectMergeMissingSignals.semanticEquivalenceProof;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function compactRecord(record) {
|
|
316
|
-
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
317
|
-
}
|
|
316
|
+
function isSemanticEquivalenceMissing(item) { return item?.proofLevel === 'semantic-equivalence-unknown' || item?.code === ProjectMergeMissingSignals.semanticEquivalenceProof; }
|
|
317
|
+
function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)); }
|
|
318
318
|
|
|
319
319
|
export { compactMissingEvidenceTelemetry, confidenceRecommendedAction, createProjectMergeAdmissionMatrixAudit, missingEvidenceItems, missingEvidenceRouteForSignal, missingEvidenceSignals, prioritizedMissingEvidence };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
function sourceTextMergeSummary(files = []) {
|
|
2
|
+
const mergedFiles = files.filter((file) => file.status === 'merged');
|
|
3
|
+
const blockedFiles = files.filter((file) => file.status === 'blocked');
|
|
4
|
+
const outputFiles = files.filter((file) => typeof file.outputSourceText === 'string');
|
|
5
|
+
return {
|
|
6
|
+
mergedFiles: mergedFiles.length,
|
|
7
|
+
blockedFiles: blockedFiles.length,
|
|
8
|
+
outputFiles: outputFiles.length,
|
|
9
|
+
sourceTextMergeCandidateFiles: mergedFiles.length,
|
|
10
|
+
sourceTextMergeBlockedFiles: blockedFiles.length,
|
|
11
|
+
sourceTextMergeOutputFiles: outputFiles.length,
|
|
12
|
+
sourceTextMergeCandidateStatus: files.length ? (blockedFiles.length ? 'failed' : 'passed') : 'absent'
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sourceTextMergeCandidateEvidenceRecord(id, summary) {
|
|
17
|
+
const passed = summary.sourceTextMergeCandidateStatus === 'passed';
|
|
18
|
+
const failed = summary.sourceTextMergeCandidateStatus === 'failed';
|
|
19
|
+
return {
|
|
20
|
+
id: `${id}_source_text_merge_candidate`,
|
|
21
|
+
kind: 'js-ts-source-text-merge-candidate',
|
|
22
|
+
level: 'source-text-merge-candidate',
|
|
23
|
+
status: passed ? 'passed' : failed ? 'failed' : 'skipped',
|
|
24
|
+
scope: 'source-files',
|
|
25
|
+
summary: sourceTextMergeCandidateEvidenceSummary(summary, passed, failed),
|
|
26
|
+
metadata: compactRecord({
|
|
27
|
+
files: summary.files,
|
|
28
|
+
sourceTextMergeCandidateFiles: summary.sourceTextMergeCandidateFiles,
|
|
29
|
+
sourceTextMergeBlockedFiles: summary.sourceTextMergeBlockedFiles,
|
|
30
|
+
sourceTextMergeOutputFiles: summary.sourceTextMergeOutputFiles,
|
|
31
|
+
outputFiles: summary.outputFiles,
|
|
32
|
+
autoMergeClaim: false,
|
|
33
|
+
semanticEquivalenceClaim: false
|
|
34
|
+
})
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sourceTextMergeMissingEvidenceItem(summary, signal, missingEvidenceItem) {
|
|
39
|
+
if (!summary.files || summary.sourceTextMergeCandidateFiles || summary.sourceTextMergeBlockedFiles) return undefined;
|
|
40
|
+
return missingEvidenceItem({
|
|
41
|
+
code: signal,
|
|
42
|
+
scope: 'source-files',
|
|
43
|
+
kind: 'source-text-merge-candidate',
|
|
44
|
+
proofLevel: 'source-text-merge-candidate',
|
|
45
|
+
action: 'review',
|
|
46
|
+
summary: 'No concrete source text merge candidate was produced; run the conservative source merge substrate before semantic graph admission.',
|
|
47
|
+
suggestedInput: { baseFiles: {}, workerFiles: {}, headFiles: {} }
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function sourceTextMergeMatrixProofStatus(level, summary) {
|
|
52
|
+
if (level !== 'source-text-merge-candidate') return undefined;
|
|
53
|
+
if (!summary.files) return 'absent';
|
|
54
|
+
if (summary.sourceTextMergeBlockedFiles) return 'failed';
|
|
55
|
+
return summary.sourceTextMergeCandidateFiles === summary.files ? 'passed' : 'missing';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function sourceTextMergeCandidateEvidenceSummary(summary, passed, failed) {
|
|
59
|
+
if (passed) return `Produced concrete source merge candidates for ${summary.sourceTextMergeCandidateFiles} file(s).`;
|
|
60
|
+
if (failed) return `Source merge candidate blocked for ${summary.sourceTextMergeBlockedFiles} file(s) before semantic admission.`;
|
|
61
|
+
return 'No source files were available for source text merge candidate production.';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function compactRecord(record) {
|
|
65
|
+
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { sourceTextMergeCandidateEvidenceRecord, sourceTextMergeMatrixProofStatus, sourceTextMergeMissingEvidenceItem, sourceTextMergeSummary };
|
|
@@ -1,6 +1,7 @@
|
|
|
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
|
import { htmlCssProjectSummary } from './js-ts-safe-project-merge-html-css-summary.js';
|
|
4
|
+
import { sourceTextMergeCandidateEvidenceRecord, sourceTextMergeSummary } from './js-ts-safe-project-merge-source-text-candidate.js';
|
|
4
5
|
|
|
5
6
|
function projectSummary(files, graphConflicts = [], hasProjectGraphDelta = false, outputDiagnosticsGate = undefined, outputDeclarationGate = undefined, outputQualityGate = undefined, moveRenameSummary = undefined, proofEvidence = undefined, symbolRenameSummary = undefined, splitMergeSummary = undefined, projectSymbolGraph = undefined) {
|
|
6
7
|
const byOperation = {};
|
|
@@ -11,9 +12,7 @@ function projectSummary(files, graphConflicts = [], hasProjectGraphDelta = false
|
|
|
11
12
|
const proofLevelStatuses = proofEvidence?.summary?.levelStatuses ?? {};
|
|
12
13
|
return {
|
|
13
14
|
files: files.length,
|
|
14
|
-
|
|
15
|
-
blockedFiles: files.filter((file) => file.status === 'blocked').length,
|
|
16
|
-
outputFiles: files.filter((file) => typeof file.outputSourceText === 'string').length,
|
|
15
|
+
...sourceTextMergeSummary(files),
|
|
17
16
|
...htmlCssProjectSummary(files),
|
|
18
17
|
projectGraphConflicts: graphConflicts.length,
|
|
19
18
|
projectGraphDeltaEvidenceIncluded: hasProjectGraphDelta ? 1 : 0, projectGraphEvidenceIncluded: projectSymbolGraph || hasProjectGraphDelta ? 1 : 0,
|
|
@@ -113,6 +112,7 @@ function projectSummaryWithConfidenceEvidence(summary, evidence = [], confidence
|
|
|
113
112
|
|
|
114
113
|
function projectEvidence(id, status, summary, context = {}) {
|
|
115
114
|
return uniqueRecords([
|
|
115
|
+
sourceTextMergeCandidateEvidenceRecord(id, summary),
|
|
116
116
|
projectMergeEvidenceRecord(id, status, summary, context),
|
|
117
117
|
graphEvidenceRecord(id, summary, context),
|
|
118
118
|
...fileAdmissionEvidenceRecords(context.fileResults),
|
|
@@ -168,6 +168,9 @@ function projectConfidence(id, status, summary, evidence = [], reasonCodes = [],
|
|
|
168
168
|
mergedFiles: summary.mergedFiles,
|
|
169
169
|
blockedFiles: summary.blockedFiles,
|
|
170
170
|
outputFiles: summary.outputFiles,
|
|
171
|
+
sourceTextMergeCandidateStatus: summary.sourceTextMergeCandidateStatus,
|
|
172
|
+
sourceTextMergeCandidateFiles: summary.sourceTextMergeCandidateFiles,
|
|
173
|
+
sourceTextMergeBlockedFiles: summary.sourceTextMergeBlockedFiles,
|
|
171
174
|
projectGraphConflicts: summary.projectGraphConflicts,
|
|
172
175
|
outputDiagnosticConflicts: summary.outputDiagnosticConflicts,
|
|
173
176
|
outputDeclarationConflicts: summary.outputDeclarationConflicts,
|
|
@@ -293,6 +296,7 @@ function confidenceLevel(score, status) {
|
|
|
293
296
|
function compactConfidenceDimensions(status, summary, context, routingCalibration = {}) {
|
|
294
297
|
return compactRecord({
|
|
295
298
|
merge: status === 'merged' ? 'merged' : 'blocked',
|
|
299
|
+
sourceText: summary.sourceTextMergeCandidateStatus ?? 'absent',
|
|
296
300
|
graph: context.hasProjectGraphEvidence ? (summary.projectGraphConflicts ? 'failed' : 'passed') : 'missing',
|
|
297
301
|
diagnostics: gateConfidenceDimension(context.outputDiagnosticsGate),
|
|
298
302
|
declarations: gateConfidenceDimension(context.outputDeclarationGate),
|
|
@@ -303,14 +307,7 @@ function compactConfidenceDimensions(status, summary, context, routingCalibratio
|
|
|
303
307
|
|
|
304
308
|
function gateConfidenceDimension(gate) { return !gate ? 'missing' : gate.status === 'passed' ? 'passed' : gate.status === 'skipped' ? 'missing' : 'failed'; }
|
|
305
309
|
|
|
306
|
-
function uniqueRecords(records) {
|
|
307
|
-
const seen = new Set();
|
|
308
|
-
return records.filter((record) => {
|
|
309
|
-
if (!record?.id || seen.has(record.id)) return false;
|
|
310
|
-
seen.add(record.id);
|
|
311
|
-
return true;
|
|
312
|
-
});
|
|
313
|
-
}
|
|
310
|
+
function uniqueRecords(records) { const seen = new Set(); return records.filter((record) => !record?.id || seen.has(record.id) ? false : (seen.add(record.id), true)); }
|
|
314
311
|
|
|
315
312
|
function uniqueStrings(values) { return [...new Set(values.filter((value) => typeof value === 'string' && value.length > 0))]; }
|
|
316
313
|
function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)); }
|
|
@@ -259,6 +259,9 @@ function mergeProjectFile(file, input, projectId, projectSymbolRenames) {
|
|
|
259
259
|
policy: file.policy ?? file.mergePolicy ?? policyForFile(input, file.sourcePath)
|
|
260
260
|
});
|
|
261
261
|
if (result.status !== 'merged') {
|
|
262
|
+
if (base === worker && base === head) {
|
|
263
|
+
return syntheticFile(file, context, base, 'unchanged-identical');
|
|
264
|
+
}
|
|
262
265
|
return maybeMergeImportSpecifierRemovalFile(file, context, result, input)
|
|
263
266
|
?? mergeBlockedFile(file, context, result);
|
|
264
267
|
}
|
package/package.json
CHANGED