@brandlab-digital/conformance 1.0.0-rc.2 → 1.0.0-rc.20
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/analytics-contract.d.ts +20 -0
- package/dist/analytics-contract.d.ts.map +1 -0
- package/dist/analytics-contract.js +211 -0
- package/dist/analytics-contract.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +13 -3
- package/dist/cli.js.map +1 -1
- package/dist/project-config-v3.d.ts +9 -1
- package/dist/project-config-v3.d.ts.map +1 -1
- package/dist/project-config-v3.js +210 -24
- package/dist/project-config-v3.js.map +1 -1
- package/dist/project-config.d.ts +1 -1
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +1 -1
- package/dist/project-config.js.map +1 -1
- package/dist/project-documentation.d.ts +28 -0
- package/dist/project-documentation.d.ts.map +1 -0
- package/dist/project-documentation.js +398 -0
- package/dist/project-documentation.js.map +1 -0
- package/dist/project.d.ts +4 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +263 -15
- package/dist/project.js.map +1 -1
- package/dist/release-catalog.d.ts.map +1 -1
- package/dist/release-catalog.js +1356 -0
- package/dist/release-catalog.js.map +1 -1
- package/dist/release-contract-compatibility.d.ts +126 -0
- package/dist/release-contract-compatibility.d.ts.map +1 -1
- package/dist/release-contract-compatibility.js +126 -0
- package/dist/release-contract-compatibility.js.map +1 -1
- package/dist/release-manifest.d.ts +1 -0
- package/dist/release-manifest.d.ts.map +1 -1
- package/dist/release-manifest.js +7 -0
- package/dist/release-manifest.js.map +1 -1
- package/dist/rendered-content.d.ts +18 -0
- package/dist/rendered-content.d.ts.map +1 -0
- package/dist/rendered-content.js +80 -0
- package/dist/rendered-content.js.map +1 -0
- package/dist/source-safety-contracts.d.ts +1 -1
- package/dist/source-safety-contracts.d.ts.map +1 -1
- package/dist/source-safety-contracts.js +5 -1
- package/dist/source-safety-contracts.js.map +1 -1
- package/package.json +19 -2
package/dist/project.js
CHANGED
|
@@ -2,12 +2,14 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { join, relative, resolve } from "node:path";
|
|
3
3
|
import { evaluateSharedPackageVersionSpecs, findForbiddenBrandlabPatterns, } from "./vitest.js";
|
|
4
4
|
import { DEFAULT_BRANDLAB_RELEASE_CATALOG, } from "./release-catalog.js";
|
|
5
|
-
import { BRANDLAB_CONFIG_V3_RULESET_ID, inspectBrandlabConfigV3, } from "./project-config-v3.js";
|
|
5
|
+
import { BRANDLAB_CONFIG_V3_RULESET_ID, BRANDLAB_CONFIG_V4_RULESET_ID, BRANDLAB_CONFIG_V5_RULESET_ID, inspectBrandlabConfigV3, } from "./project-config-v3.js";
|
|
6
6
|
import { BRANDLAB_CONFIG_V2_RULESET_ID, inspectBrandlabConfigV2 as inspectImmutableBrandlabConfigV2, } from "./project-config-v2-contract.js";
|
|
7
7
|
import { BRANDLAB_DEPRECATED_SCHEMA_SOURCE_PATTERNS, BRANDLAB_SCHEMA_HYGIENE_V3_RULESET_ID, } from "./schema-hygiene.js";
|
|
8
8
|
import { BRANDLAB_SOURCE_SAFETY_V2_PATTERNS, BRANDLAB_SOURCE_SAFETY_V2_RULESET_ID, sourceSafetyRulesetForArchitecture, targetOnlySourceSafetyPatterns, } from "./source-safety-contracts.js";
|
|
9
9
|
import { inspectLegacyArchitectureContract, legacyArchitectureRulesetId, targetOnlyLegacyArchitectureIssues, } from "./legacy-architecture-contracts.js";
|
|
10
10
|
import { BRANDLAB_SHARED_PACKAGE_NAMES, compareBrandlabSemver, digestBrandlabAuthority, isBrandlabSemver, validateBrandlabReleaseCatalog, validateBrandlabRuntimeReleaseCatalog, validateBrandlabRuntimeReleaseManifestSubsetAgainstCatalog, validateBrandlabSupportPolicy, } from "./release-manifest.js";
|
|
11
|
+
import { BRANDLAB_PROJECT_DOCUMENTATION_RULESET_ID, inspectBrandlabProjectDocumentation, } from "./project-documentation.js";
|
|
12
|
+
import { BRANDLAB_ANALYTICS_V3_RULESET_ID, inspectBrandlabAnalyticsV3, } from "./analytics-contract.js";
|
|
11
13
|
export const BRANDLAB_CONFORMANCE_SCHEMA_VERSION = "brandlab.conformance.v1";
|
|
12
14
|
export const BRANDLAB_CONFORMANCE_EVALUATOR_VERSION = "control-plane-v1";
|
|
13
15
|
export const BRANDLAB_ARCHITECTURE_DISPATCH_RULESET_ID = "version-aware-architecture-dispatch-v1";
|
|
@@ -15,7 +17,19 @@ const LEGACY_ARCHITECTURE_EVALUATOR_CONTRACT = "architecture-v2";
|
|
|
15
17
|
const LEGACY_CONFIGURATION_CONTRACT = "legacy-config-v1";
|
|
16
18
|
const CONFIGURATION_V2_CONTRACT = "project-config-v2";
|
|
17
19
|
const CONFIGURATION_V3_CONTRACT = "project-config-v3";
|
|
20
|
+
const CONFIGURATION_V4_CONTRACT = "project-config-v4";
|
|
21
|
+
const CONFIGURATION_V5_CONTRACT = "project-config-v5";
|
|
18
22
|
const SEO_V3_CONTRACT = "seo-v3";
|
|
23
|
+
const SEO_V4_CONTRACT = "seo-v4";
|
|
24
|
+
const ARCHITECTURE_V5_CONTRACT = "architecture-v5";
|
|
25
|
+
const ANALYTICS_V3_CONTRACT = "analytics-v3";
|
|
26
|
+
const ANALYTICS_V4_CONTRACT = "analytics-v4";
|
|
27
|
+
function isSeoV3Compatible(contract) {
|
|
28
|
+
return contract === SEO_V3_CONTRACT || contract === SEO_V4_CONTRACT;
|
|
29
|
+
}
|
|
30
|
+
function isAnalyticsV3Compatible(contract) {
|
|
31
|
+
return contract === ANALYTICS_V3_CONTRACT || contract === ANALYTICS_V4_CONTRACT;
|
|
32
|
+
}
|
|
19
33
|
const RUNTIME_PACKAGE_FIELDS = [
|
|
20
34
|
["next", "next"],
|
|
21
35
|
["react", "react"],
|
|
@@ -79,6 +93,35 @@ export function evaluateBrandlabProject(options) {
|
|
|
79
93
|
targetRelease,
|
|
80
94
|
architecture: options.architecture,
|
|
81
95
|
});
|
|
96
|
+
const documentationFingerprint = evaluateApplicableProjectDocumentationContracts({
|
|
97
|
+
root,
|
|
98
|
+
findings,
|
|
99
|
+
installedManifest,
|
|
100
|
+
targetManifest,
|
|
101
|
+
});
|
|
102
|
+
const analyticsFingerprint = evaluateApplicableAnalyticsContracts({
|
|
103
|
+
root,
|
|
104
|
+
findings,
|
|
105
|
+
installedManifest,
|
|
106
|
+
targetManifest,
|
|
107
|
+
});
|
|
108
|
+
if (installedManifest) {
|
|
109
|
+
addContactUploadFilenameFindings({
|
|
110
|
+
root,
|
|
111
|
+
findings,
|
|
112
|
+
manifest: installedManifest,
|
|
113
|
+
classification: "maintenance",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (targetManifest &&
|
|
117
|
+
targetManifest.releaseVersion !== installedManifest?.releaseVersion) {
|
|
118
|
+
addContactUploadFilenameFindings({
|
|
119
|
+
root,
|
|
120
|
+
findings,
|
|
121
|
+
manifest: targetManifest,
|
|
122
|
+
classification: "migration",
|
|
123
|
+
});
|
|
124
|
+
}
|
|
82
125
|
const sourceRoot = join(root, "src");
|
|
83
126
|
const installedSourceSafety = sourceSafetyRulesetForArchitecture(installedManifest?.contracts.architecture);
|
|
84
127
|
const targetSourceSafety = sourceSafetyRulesetForArchitecture(targetManifest?.contracts.architecture);
|
|
@@ -140,17 +183,17 @@ export function evaluateBrandlabProject(options) {
|
|
|
140
183
|
},
|
|
141
184
|
});
|
|
142
185
|
}
|
|
143
|
-
if (installedManifest?.contracts.seo
|
|
186
|
+
if (isSeoV3Compatible(installedManifest?.contracts.seo)) {
|
|
144
187
|
addSourcePatternFindings({
|
|
145
188
|
root,
|
|
146
189
|
sourceRoot,
|
|
147
190
|
findings,
|
|
148
191
|
patterns: BRANDLAB_DEPRECATED_SCHEMA_SOURCE_PATTERNS,
|
|
149
192
|
classification: "maintenance",
|
|
150
|
-
contract: { name: "seo", version:
|
|
193
|
+
contract: { name: "seo", version: installedManifest.contracts.seo },
|
|
151
194
|
});
|
|
152
195
|
}
|
|
153
|
-
if (targetManifest?.contracts.seo
|
|
196
|
+
if (isSeoV3Compatible(targetManifest?.contracts.seo) &&
|
|
154
197
|
targetManifest.releaseVersion !== installedManifest?.releaseVersion) {
|
|
155
198
|
addSourcePatternFindings({
|
|
156
199
|
root,
|
|
@@ -158,7 +201,7 @@ export function evaluateBrandlabProject(options) {
|
|
|
158
201
|
findings,
|
|
159
202
|
patterns: BRANDLAB_DEPRECATED_SCHEMA_SOURCE_PATTERNS,
|
|
160
203
|
classification: "migration",
|
|
161
|
-
contract: { name: "seo", version:
|
|
204
|
+
contract: { name: "seo", version: targetManifest.contracts.seo },
|
|
162
205
|
});
|
|
163
206
|
}
|
|
164
207
|
}
|
|
@@ -175,11 +218,21 @@ export function evaluateBrandlabProject(options) {
|
|
|
175
218
|
rulesets: {
|
|
176
219
|
configurationV2: BRANDLAB_CONFIG_V2_RULESET_ID,
|
|
177
220
|
configurationV3: BRANDLAB_CONFIG_V3_RULESET_ID,
|
|
221
|
+
configurationV4: BRANDLAB_CONFIG_V4_RULESET_ID,
|
|
222
|
+
configurationV5: BRANDLAB_CONFIG_V5_RULESET_ID,
|
|
178
223
|
seoV3: BRANDLAB_SCHEMA_HYGIENE_V3_RULESET_ID,
|
|
179
224
|
installedSourceSafety: installedSourceSafety?.id ?? null,
|
|
180
225
|
targetSourceSafety: targetSourceSafety?.id ?? null,
|
|
181
226
|
installedLegacyArchitecture: legacyArchitectureRulesetId(installedManifest?.contracts.architecture),
|
|
182
227
|
targetLegacyArchitecture: legacyArchitectureRulesetId(targetManifest?.contracts.architecture),
|
|
228
|
+
projectDocumentation: installedManifest?.contracts.architecture === ARCHITECTURE_V5_CONTRACT ||
|
|
229
|
+
targetManifest?.contracts.architecture === ARCHITECTURE_V5_CONTRACT
|
|
230
|
+
? BRANDLAB_PROJECT_DOCUMENTATION_RULESET_ID
|
|
231
|
+
: null,
|
|
232
|
+
analyticsV3: isAnalyticsV3Compatible(installedManifest?.contracts.analytics) ||
|
|
233
|
+
isAnalyticsV3Compatible(targetManifest?.contracts.analytics)
|
|
234
|
+
? BRANDLAB_ANALYTICS_V3_RULESET_ID
|
|
235
|
+
: null,
|
|
183
236
|
},
|
|
184
237
|
});
|
|
185
238
|
const implementationFingerprint = digestBrandlabAuthority({
|
|
@@ -187,6 +240,8 @@ export function evaluateBrandlabProject(options) {
|
|
|
187
240
|
packageLock: packageLock.fingerprint,
|
|
188
241
|
brandlabConfig: readOptionalText(join(root, "brandlab.config.ts")),
|
|
189
242
|
architecture: architectureFingerprint,
|
|
243
|
+
documentation: documentationFingerprint,
|
|
244
|
+
analytics: analyticsFingerprint,
|
|
190
245
|
evidence: sortedFindings.map(({ ruleId, classification, severity, path, line }) => ({
|
|
191
246
|
ruleId,
|
|
192
247
|
classification,
|
|
@@ -210,6 +265,85 @@ export function evaluateBrandlabProject(options) {
|
|
|
210
265
|
advisory: summarize(sortedFindings, "advisory"),
|
|
211
266
|
};
|
|
212
267
|
}
|
|
268
|
+
function evaluateApplicableProjectDocumentationContracts(options) {
|
|
269
|
+
const installedArchitecture = options.installedManifest?.contracts.architecture ?? null;
|
|
270
|
+
const targetArchitecture = options.targetManifest?.contracts.architecture ?? null;
|
|
271
|
+
if (installedArchitecture !== ARCHITECTURE_V5_CONTRACT &&
|
|
272
|
+
targetArchitecture !== ARCHITECTURE_V5_CONTRACT) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
const report = inspectBrandlabProjectDocumentation(options.root);
|
|
276
|
+
if (installedArchitecture === ARCHITECTURE_V5_CONTRACT) {
|
|
277
|
+
for (const issue of report.issues) {
|
|
278
|
+
options.findings.push(mapProjectDocumentationIssue(issue, "maintenance"));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else if (targetArchitecture === ARCHITECTURE_V5_CONTRACT) {
|
|
282
|
+
for (const issue of report.issues) {
|
|
283
|
+
options.findings.push(mapProjectDocumentationIssue(issue, "migration"));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
rulesetId: report.rulesetId,
|
|
288
|
+
files: report.files,
|
|
289
|
+
applicableRuleIds: report.issues.map((issue) => issue.ruleId).sort(),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function mapProjectDocumentationIssue(issue, classification) {
|
|
293
|
+
return {
|
|
294
|
+
ruleId: issue.ruleId,
|
|
295
|
+
surface: issue.surface,
|
|
296
|
+
classification,
|
|
297
|
+
severity: issue.severity,
|
|
298
|
+
contract: { name: "architecture", version: ARCHITECTURE_V5_CONTRACT },
|
|
299
|
+
evidenceKind: issue.evidenceKind,
|
|
300
|
+
...(issue.path ? { path: issue.path } : {}),
|
|
301
|
+
...(issue.line ? { line: issue.line } : {}),
|
|
302
|
+
expected: issue.expected,
|
|
303
|
+
actual: issue.actual,
|
|
304
|
+
remediation: issue.remediation,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function evaluateApplicableAnalyticsContracts(options) {
|
|
308
|
+
const installedAnalytics = options.installedManifest?.contracts.analytics ?? null;
|
|
309
|
+
const targetAnalytics = options.targetManifest?.contracts.analytics ?? null;
|
|
310
|
+
if (!isAnalyticsV3Compatible(installedAnalytics) &&
|
|
311
|
+
!isAnalyticsV3Compatible(targetAnalytics)) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
const inspection = inspectBrandlabAnalyticsV3(options.root);
|
|
315
|
+
if (isAnalyticsV3Compatible(installedAnalytics)) {
|
|
316
|
+
for (const issue of inspection.issues) {
|
|
317
|
+
options.findings.push(mapAnalyticsV3Issue(issue, "maintenance", installedAnalytics));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else if (isAnalyticsV3Compatible(targetAnalytics)) {
|
|
321
|
+
for (const issue of inspection.issues) {
|
|
322
|
+
options.findings.push(mapAnalyticsV3Issue(issue, "migration", targetAnalytics));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
rulesetId: inspection.rulesetId,
|
|
327
|
+
websiteCallsDeclared: inspection.websiteCallsDeclared,
|
|
328
|
+
leadDiagnosticsDeclared: inspection.leadDiagnosticsDeclared,
|
|
329
|
+
applicableRuleIds: inspection.issues.map((issue) => issue.ruleId).sort(),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function mapAnalyticsV3Issue(issue, classification, contractVersion) {
|
|
333
|
+
return {
|
|
334
|
+
ruleId: issue.ruleId,
|
|
335
|
+
surface: issue.surface,
|
|
336
|
+
classification,
|
|
337
|
+
severity: issue.severity,
|
|
338
|
+
contract: { name: "analytics", version: contractVersion },
|
|
339
|
+
evidenceKind: issue.evidenceKind,
|
|
340
|
+
...(issue.path ? { path: issue.path } : {}),
|
|
341
|
+
...(issue.line ? { line: issue.line } : {}),
|
|
342
|
+
expected: issue.expected,
|
|
343
|
+
actual: issue.actual,
|
|
344
|
+
remediation: issue.remediation,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
213
347
|
function addSourcePatternFindings(options) {
|
|
214
348
|
for (const match of findForbiddenBrandlabPatterns({
|
|
215
349
|
roots: [options.sourceRoot],
|
|
@@ -674,6 +808,13 @@ function addInstalledRuntimeFindings(options) {
|
|
|
674
808
|
path: "package.json",
|
|
675
809
|
}));
|
|
676
810
|
}
|
|
811
|
+
addSharpRuntimeFindings({
|
|
812
|
+
findings: options.findings,
|
|
813
|
+
packageJson: options.packageJson,
|
|
814
|
+
packageLock: options.packageLock,
|
|
815
|
+
manifest: options.manifest,
|
|
816
|
+
classification: "maintenance",
|
|
817
|
+
});
|
|
677
818
|
}
|
|
678
819
|
function addTargetRuntimeFindings(options) {
|
|
679
820
|
if (!options.packageJson)
|
|
@@ -713,6 +854,16 @@ function addTargetRuntimeFindings(options) {
|
|
|
713
854
|
if (options.packageJson.packageManager !== options.targetManifest.runtime.packageManager) {
|
|
714
855
|
runtimeMismatches.push(`packageManager(expected=${options.targetManifest.runtime.packageManager},actual=${options.packageJson.packageManager ?? "missing"})`);
|
|
715
856
|
}
|
|
857
|
+
const targetSharp = options.targetManifest.runtime.sharp;
|
|
858
|
+
if (targetSharp) {
|
|
859
|
+
const actualOverride = options.packageJson.overrides?.sharp ?? null;
|
|
860
|
+
const sharpResolutions = options.packageLock.sharpResolutions;
|
|
861
|
+
if (actualOverride !== targetSharp ||
|
|
862
|
+
sharpResolutions.length !== 1 ||
|
|
863
|
+
sharpResolutions[0]?.version !== targetSharp) {
|
|
864
|
+
runtimeMismatches.push(`sharp(expected=${targetSharp},override=${actualOverride ?? "missing"},resolutions=${formatSharpResolutions(sharpResolutions)})`);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
716
867
|
if (runtimeMismatches.length > 0) {
|
|
717
868
|
options.findings.push(migrationRuntimeFinding({
|
|
718
869
|
ruleId: "brandlab-migration-runtime-baseline",
|
|
@@ -722,6 +873,64 @@ function addTargetRuntimeFindings(options) {
|
|
|
722
873
|
}));
|
|
723
874
|
}
|
|
724
875
|
}
|
|
876
|
+
function addSharpRuntimeFindings(options) {
|
|
877
|
+
const expected = options.manifest.runtime.sharp;
|
|
878
|
+
if (!expected)
|
|
879
|
+
return;
|
|
880
|
+
const actualOverride = options.packageJson.overrides?.sharp ?? null;
|
|
881
|
+
if (actualOverride !== expected) {
|
|
882
|
+
options.findings.push(runtimeFinding({
|
|
883
|
+
ruleId: "brandlab-runtime-sharp-override",
|
|
884
|
+
expected: `overrides.sharp=${expected}`,
|
|
885
|
+
actual: `overrides.sharp=${actualOverride ?? "missing"}.`,
|
|
886
|
+
remediation: "Add the release-owned Sharp override so Next.js and site-next use one security-patched native runtime.",
|
|
887
|
+
path: "package.json",
|
|
888
|
+
}));
|
|
889
|
+
}
|
|
890
|
+
if (options.packageLock.state !== "valid")
|
|
891
|
+
return;
|
|
892
|
+
if (options.packageLock.sharpResolutions.length !== 1 ||
|
|
893
|
+
options.packageLock.sharpResolutions[0]?.version !== expected) {
|
|
894
|
+
options.findings.push(runtimeFinding({
|
|
895
|
+
ruleId: "brandlab-runtime-sharp-resolution",
|
|
896
|
+
expected: `one sharp@${expected} lockfile resolution`,
|
|
897
|
+
actual: formatSharpResolutions(options.packageLock.sharpResolutions),
|
|
898
|
+
remediation: "Regenerate package-lock.json after applying the exact release-owned Sharp override.",
|
|
899
|
+
path: "package-lock.json",
|
|
900
|
+
}));
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
function addContactUploadFilenameFindings(options) {
|
|
904
|
+
if (!options.manifest.capabilities.includes("client-safe-contact-upload-filenames")) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
const path = "src/lib/contact/imageUploads.ts";
|
|
908
|
+
const source = readOptionalText(join(options.root, path));
|
|
909
|
+
// Raw File objects already retain their reviewed names. This rule is only
|
|
910
|
+
// relevant when a project owns a client-side image processing adapter.
|
|
911
|
+
if (!source || /\bnormalizeContactUploadFile\s*\(/.test(source))
|
|
912
|
+
return;
|
|
913
|
+
options.findings.push({
|
|
914
|
+
ruleId: "brandlab-contact-upload-filename-normalization",
|
|
915
|
+
surface: "contact",
|
|
916
|
+
classification: options.classification,
|
|
917
|
+
severity: "blocker",
|
|
918
|
+
contract: {
|
|
919
|
+
name: "contact",
|
|
920
|
+
version: options.manifest.contracts.contact,
|
|
921
|
+
},
|
|
922
|
+
evidenceKind: "static",
|
|
923
|
+
path,
|
|
924
|
+
expected: "Compressed contact images are wrapped with normalizeContactUploadFile before FormData submission.",
|
|
925
|
+
actual: "The contact upload module does not use the shared filename normalizer.",
|
|
926
|
+
remediation: "Use normalizeContactUploadFile(original, processed) from @brandlab-digital/site-next/contact/client so anonymous browser Blobs retain a valid reviewed filename.",
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
function formatSharpResolutions(resolutions) {
|
|
930
|
+
return resolutions.length === 0
|
|
931
|
+
? "none"
|
|
932
|
+
: resolutions.map((entry) => `${entry.path}=${entry.version ?? "missing"}`).join(", ");
|
|
933
|
+
}
|
|
725
934
|
function runtimeFinding(options) {
|
|
726
935
|
return {
|
|
727
936
|
ruleId: options.ruleId,
|
|
@@ -760,10 +969,14 @@ function evaluateApplicableArchitectureContracts(options) {
|
|
|
760
969
|
configV2Inspection ??= inspectImmutableBrandlabConfigV2(options.root);
|
|
761
970
|
return configV2Inspection;
|
|
762
971
|
};
|
|
763
|
-
|
|
764
|
-
const inspectConfigV3 = () => {
|
|
765
|
-
|
|
766
|
-
|
|
972
|
+
const configV3Inspections = new Map();
|
|
973
|
+
const inspectConfigV3 = (contractVersion) => {
|
|
974
|
+
const cached = configV3Inspections.get(contractVersion);
|
|
975
|
+
if (cached)
|
|
976
|
+
return cached;
|
|
977
|
+
const inspection = inspectBrandlabConfigV3(options.root, { contractVersion });
|
|
978
|
+
configV3Inspections.set(contractVersion, inspection);
|
|
979
|
+
return inspection;
|
|
767
980
|
};
|
|
768
981
|
const legacyInspections = new Map();
|
|
769
982
|
let legacyArchitectureInput;
|
|
@@ -793,7 +1006,19 @@ function evaluateApplicableArchitectureContracts(options) {
|
|
|
793
1006
|
}
|
|
794
1007
|
}
|
|
795
1008
|
else if (installedConfiguration === CONFIGURATION_V3_CONTRACT) {
|
|
796
|
-
const inspection = inspectConfigV3();
|
|
1009
|
+
const inspection = inspectConfigV3(CONFIGURATION_V3_CONTRACT);
|
|
1010
|
+
for (const issue of inspection.issues) {
|
|
1011
|
+
options.findings.push(mapConfigIssue(issue, "maintenance", options.installedManifest?.contracts));
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
else if (installedConfiguration === CONFIGURATION_V4_CONTRACT) {
|
|
1015
|
+
const inspection = inspectConfigV3(CONFIGURATION_V4_CONTRACT);
|
|
1016
|
+
for (const issue of inspection.issues) {
|
|
1017
|
+
options.findings.push(mapConfigIssue(issue, "maintenance", options.installedManifest?.contracts));
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
else if (installedConfiguration === CONFIGURATION_V5_CONTRACT) {
|
|
1021
|
+
const inspection = inspectConfigV3(CONFIGURATION_V5_CONTRACT);
|
|
797
1022
|
for (const issue of inspection.issues) {
|
|
798
1023
|
options.findings.push(mapConfigIssue(issue, "maintenance", options.installedManifest?.contracts));
|
|
799
1024
|
}
|
|
@@ -826,9 +1051,9 @@ function evaluateApplicableArchitectureContracts(options) {
|
|
|
826
1051
|
// supported target release is explicitly selected.
|
|
827
1052
|
const configSource = readOptionalText(join(options.root, "brandlab.config.ts"));
|
|
828
1053
|
if (/\bdefineBrandlabProject\s*\(/.test(configSource ?? "")) {
|
|
829
|
-
for (const issue of inspectConfigV3().issues) {
|
|
1054
|
+
for (const issue of inspectConfigV3(CONFIGURATION_V5_CONTRACT).issues) {
|
|
830
1055
|
options.findings.push(mapConfigIssue(issue, "advisory", {
|
|
831
|
-
configuration:
|
|
1056
|
+
configuration: CONFIGURATION_V5_CONTRACT,
|
|
832
1057
|
}));
|
|
833
1058
|
}
|
|
834
1059
|
}
|
|
@@ -846,7 +1071,17 @@ function evaluateApplicableArchitectureContracts(options) {
|
|
|
846
1071
|
}
|
|
847
1072
|
}
|
|
848
1073
|
else if (hasDistinctTarget && targetConfiguration === CONFIGURATION_V3_CONTRACT) {
|
|
849
|
-
for (const issue of inspectConfigV3().issues) {
|
|
1074
|
+
for (const issue of inspectConfigV3(CONFIGURATION_V3_CONTRACT).issues) {
|
|
1075
|
+
options.findings.push(mapConfigIssue(issue, "migration", options.targetManifest?.contracts));
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
else if (hasDistinctTarget && targetConfiguration === CONFIGURATION_V4_CONTRACT) {
|
|
1079
|
+
for (const issue of inspectConfigV3(CONFIGURATION_V4_CONTRACT).issues) {
|
|
1080
|
+
options.findings.push(mapConfigIssue(issue, "migration", options.targetManifest?.contracts));
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
else if (hasDistinctTarget && targetConfiguration === CONFIGURATION_V5_CONTRACT) {
|
|
1084
|
+
for (const issue of inspectConfigV3(CONFIGURATION_V5_CONTRACT).issues) {
|
|
850
1085
|
options.findings.push(mapConfigIssue(issue, "migration", options.targetManifest?.contracts));
|
|
851
1086
|
}
|
|
852
1087
|
}
|
|
@@ -867,7 +1102,9 @@ function evaluateApplicableArchitectureContracts(options) {
|
|
|
867
1102
|
}
|
|
868
1103
|
}
|
|
869
1104
|
const inspectedConfigV2 = configV2Inspection;
|
|
870
|
-
const inspectedConfigV3 =
|
|
1105
|
+
const inspectedConfigV3 = (configV3Inspections.get(CONFIGURATION_V4_CONTRACT) ??
|
|
1106
|
+
configV3Inspections.get(CONFIGURATION_V3_CONTRACT) ??
|
|
1107
|
+
null);
|
|
871
1108
|
return {
|
|
872
1109
|
evaluator: BRANDLAB_ARCHITECTURE_DISPATCH_RULESET_ID,
|
|
873
1110
|
installedContract: options.installedManifest?.contracts.architecture ?? null,
|
|
@@ -1050,7 +1287,7 @@ function readPackageLock(root) {
|
|
|
1050
1287
|
const rootDevDependencies = stringRecord(rootPackage.devDependencies);
|
|
1051
1288
|
const rootEngines = stringRecord(rootPackage.engines);
|
|
1052
1289
|
const resolvedPackages = new Map();
|
|
1053
|
-
for (const packageName of [...BRANDLAB_SHARED_PACKAGE_NAMES, ...RUNTIME_PACKAGE_FIELDS.map(([name]) => name)]) {
|
|
1290
|
+
for (const packageName of [...BRANDLAB_SHARED_PACKAGE_NAMES, ...RUNTIME_PACKAGE_FIELDS.map(([name]) => name), "sharp"]) {
|
|
1054
1291
|
const entry = parsed.packages[`node_modules/${packageName}`];
|
|
1055
1292
|
if (!isObjectRecord(entry))
|
|
1056
1293
|
continue;
|
|
@@ -1061,6 +1298,13 @@ function readPackageLock(root) {
|
|
|
1061
1298
|
linked: entry.link === true,
|
|
1062
1299
|
});
|
|
1063
1300
|
}
|
|
1301
|
+
const sharpResolutions = Object.entries(parsed.packages)
|
|
1302
|
+
.filter(([packagePath]) => packagePath === "node_modules/sharp" || packagePath.endsWith("/node_modules/sharp"))
|
|
1303
|
+
.map(([packagePath, entry]) => ({
|
|
1304
|
+
path: packagePath,
|
|
1305
|
+
version: isObjectRecord(entry) && typeof entry.version === "string" ? entry.version : null,
|
|
1306
|
+
}))
|
|
1307
|
+
.sort((left, right) => left.path.localeCompare(right.path));
|
|
1064
1308
|
return {
|
|
1065
1309
|
state: "valid",
|
|
1066
1310
|
lockfileVersion,
|
|
@@ -1068,6 +1312,7 @@ function readPackageLock(root) {
|
|
|
1068
1312
|
rootDevDependencies,
|
|
1069
1313
|
rootEngines,
|
|
1070
1314
|
resolvedPackages,
|
|
1315
|
+
sharpResolutions,
|
|
1071
1316
|
fingerprint: {
|
|
1072
1317
|
state: "valid",
|
|
1073
1318
|
lockfileVersion,
|
|
@@ -1080,6 +1325,7 @@ function readPackageLock(root) {
|
|
|
1080
1325
|
rootDevDependencies,
|
|
1081
1326
|
rootEngines,
|
|
1082
1327
|
resolvedPackages,
|
|
1328
|
+
sharpResolutions,
|
|
1083
1329
|
fingerprint: {},
|
|
1084
1330
|
}, packageName)])),
|
|
1085
1331
|
node: rootEngines.node ?? null,
|
|
@@ -1088,6 +1334,7 @@ function readPackageLock(root) {
|
|
|
1088
1334
|
packageName,
|
|
1089
1335
|
{ version: entry.version, linked: entry.linked },
|
|
1090
1336
|
])),
|
|
1337
|
+
sharp: sharpResolutions,
|
|
1091
1338
|
},
|
|
1092
1339
|
};
|
|
1093
1340
|
}
|
|
@@ -1099,6 +1346,7 @@ function emptyPackageLockInspection(state, extra = {}) {
|
|
|
1099
1346
|
rootDevDependencies: {},
|
|
1100
1347
|
rootEngines: {},
|
|
1101
1348
|
resolvedPackages: new Map(),
|
|
1349
|
+
sharpResolutions: [],
|
|
1102
1350
|
fingerprint: { state, ...extra },
|
|
1103
1351
|
};
|
|
1104
1352
|
}
|