forgeos 0.1.0-alpha.0 → 0.1.0-alpha.2
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/.npmignore +9 -1
- package/AGENTS.md +6 -1
- package/CHANGELOG.md +30 -0
- package/CONTRIBUTING.md +22 -1
- package/README.md +30 -3
- package/bin/forge.mjs +4 -3
- package/package.json +3 -1
- package/packages/eslint-plugin-forge/index.ts +15 -15
- package/packages/eslint-plugin-forge/package.json +10 -10
- package/packages/eslint-plugin-forge/src/check-source.ts +95 -95
- package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -24
- package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -93
- package/src/forge/_generated/actionSubscriptions.json +2 -2
- package/src/forge/_generated/actionSubscriptions.ts +3 -3
- package/src/forge/_generated/agentAdapterManifest.json +2 -2
- package/src/forge/_generated/agentAdapterManifest.ts +3 -3
- package/src/forge/_generated/agentContract.json +2 -2
- package/src/forge/_generated/agentContract.ts +6786 -2
- package/src/forge/_generated/agentQuickstart.md +1 -1
- package/src/forge/_generated/aiContext.ts +1 -1
- package/src/forge/_generated/aiModels.json +1 -1
- package/src/forge/_generated/aiModels.ts +1 -1
- package/src/forge/_generated/aiProviders.json +1 -1
- package/src/forge/_generated/aiProviders.ts +1 -1
- package/src/forge/_generated/aiRegistry.json +2 -2
- package/src/forge/_generated/aiRegistry.ts +3 -3
- package/src/forge/_generated/api.json +2 -2
- package/src/forge/_generated/api.ts +1 -1
- package/src/forge/_generated/appGraph.json +2 -2
- package/src/forge/_generated/appGraph.ts +1297 -1141
- package/src/forge/_generated/appMap.md +1 -1
- package/src/forge/_generated/artifactManifest.json +2 -2
- package/src/forge/_generated/artifactManifest.ts +2 -2
- package/src/forge/_generated/authClaims.json +1 -1
- package/src/forge/_generated/authClaims.ts +1 -1
- package/src/forge/_generated/authConfig.json +1 -1
- package/src/forge/_generated/authConfig.ts +1 -1
- package/src/forge/_generated/authContext.ts +1 -1
- package/src/forge/_generated/authRegistry.json +1 -1
- package/src/forge/_generated/authRegistry.ts +1 -1
- package/src/forge/_generated/buildInfo.json +2 -2
- package/src/forge/_generated/buildInfo.ts +4 -4
- package/src/forge/_generated/capabilityMap.json +2 -2
- package/src/forge/_generated/capabilityMap.md +1 -1
- package/src/forge/_generated/capabilityMap.ts +2 -2
- package/src/forge/_generated/client.ts +1 -1
- package/src/forge/_generated/clientApi.ts +1 -1
- package/src/forge/_generated/clientManifest.json +2 -2
- package/src/forge/_generated/clientManifest.ts +3 -3
- package/src/forge/_generated/clientTypes.ts +1 -1
- package/src/forge/_generated/configRegistry.json +1 -1
- package/src/forge/_generated/configRegistry.ts +1 -1
- package/src/forge/_generated/dataGraph.json +2 -2
- package/src/forge/_generated/dataGraph.ts +3 -3
- package/src/forge/_generated/db.json +1 -1
- package/src/forge/_generated/db.ts +1 -1
- package/src/forge/_generated/dbSecurityManifest.json +1 -1
- package/src/forge/_generated/dbSecurityManifest.ts +1 -1
- package/src/forge/_generated/dbSessionContext.json +1 -1
- package/src/forge/_generated/dbSessionContext.ts +1 -1
- package/src/forge/_generated/deployManifest.json +2 -2
- package/src/forge/_generated/deployManifest.ts +7 -7
- package/src/forge/_generated/devManifest.json +2 -2
- package/src/forge/_generated/devManifest.ts +3 -3
- package/src/forge/_generated/envSchema.json +1 -1
- package/src/forge/_generated/envSchema.ts +1 -1
- package/src/forge/_generated/frontendGraph.json +1 -1
- package/src/forge/_generated/frontendGraph.ts +1 -1
- package/src/forge/_generated/importGuards.json +2 -2
- package/src/forge/_generated/importGuards.ts +35 -1
- package/src/forge/_generated/index.ts +1 -1
- package/src/forge/_generated/liveProductionManifest.json +1 -1
- package/src/forge/_generated/liveProductionManifest.ts +1 -1
- package/src/forge/_generated/liveProtocol.json +1 -1
- package/src/forge/_generated/liveProtocol.ts +1 -1
- package/src/forge/_generated/liveQueryRegistry.json +2 -2
- package/src/forge/_generated/liveQueryRegistry.ts +3 -3
- package/src/forge/_generated/liveTransportConfig.json +1 -1
- package/src/forge/_generated/liveTransportConfig.ts +1 -1
- package/src/forge/_generated/makeRegistry.json +2 -2
- package/src/forge/_generated/makeRegistry.ts +2 -2
- package/src/forge/_generated/makeTemplates.json +1 -1
- package/src/forge/_generated/makeTemplates.ts +1 -1
- package/src/forge/_generated/mockMap.json +1 -1
- package/src/forge/_generated/mockMap.ts +1 -1
- package/src/forge/_generated/operationPlaybooks.md +7 -5
- package/src/forge/_generated/packageGraph.json +2 -2
- package/src/forge/_generated/packageGraph.ts +90964 -14284
- package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
- package/src/forge/_generated/permissionMatrix.json +2 -2
- package/src/forge/_generated/permissionMatrix.ts +3 -3
- package/src/forge/_generated/policyRegistry.json +2 -2
- package/src/forge/_generated/policyRegistry.ts +3 -3
- package/src/forge/_generated/queryRegistry.json +2 -2
- package/src/forge/_generated/queryRegistry.ts +3 -3
- package/src/forge/_generated/react.d.ts +1 -1
- package/src/forge/_generated/react.ts +1 -1
- package/src/forge/_generated/reactManifest.json +2 -2
- package/src/forge/_generated/reactManifest.ts +3 -3
- package/src/forge/_generated/releaseManifest.json +2 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/_generated/rlsPolicies.json +1 -1
- package/src/forge/_generated/rlsPolicies.sql +1 -1
- package/src/forge/_generated/rlsPolicies.ts +1 -1
- package/src/forge/_generated/runtimeGraph.json +2 -2
- package/src/forge/_generated/runtimeGraph.ts +3 -3
- package/src/forge/_generated/runtimeMatrix.json +2 -2
- package/src/forge/_generated/runtimeMatrix.ts +106177 -7917
- package/src/forge/_generated/runtimeRegistry.ts +1 -1
- package/src/forge/_generated/runtimeRules.md +1 -1
- package/src/forge/_generated/secretRegistry.json +1 -1
- package/src/forge/_generated/secretRegistry.ts +1 -1
- package/src/forge/_generated/secretsContext.ts +1 -1
- package/src/forge/_generated/serverApi.ts +1 -1
- package/src/forge/_generated/sourceMapManifest.json +2 -2
- package/src/forge/_generated/sourceMapManifest.ts +2 -2
- package/src/forge/_generated/sqlPlan.json +1 -1
- package/src/forge/_generated/sqlPlan.ts +1 -1
- package/src/forge/_generated/subscriptionManifest.json +2 -2
- package/src/forge/_generated/subscriptionManifest.ts +3 -3
- package/src/forge/_generated/symbolicationManifest.json +2 -2
- package/src/forge/_generated/symbolicationManifest.ts +2 -2
- package/src/forge/_generated/telemetryRegistry.json +2 -2
- package/src/forge/_generated/telemetryRegistry.ts +3 -3
- package/src/forge/_generated/telemetrySinks.json +2 -2
- package/src/forge/_generated/telemetrySinks.ts +2 -2
- package/src/forge/_generated/tenantScope.json +2 -2
- package/src/forge/_generated/tenantScope.ts +3 -3
- package/src/forge/_generated/testGraph.json +2 -2
- package/src/forge/_generated/testGraph.ts +129 -75
- package/src/forge/_generated/testPlanRegistry.json +2 -2
- package/src/forge/_generated/testPlanRegistry.ts +2 -2
- package/src/forge/_generated/uiRoutes.json +1 -1
- package/src/forge/_generated/uiRoutes.ts +1 -1
- package/src/forge/_generated/uiScenarios.json +1 -1
- package/src/forge/_generated/uiScenarios.ts +1 -1
- package/src/forge/_generated/uiTestManifest.json +2 -2
- package/src/forge/_generated/uiTestManifest.ts +2 -2
- package/src/forge/_generated/workflowRegistry.json +2 -2
- package/src/forge/_generated/workflowRegistry.ts +3 -3
- package/src/forge/_generated/workflowSubscriptions.json +2 -2
- package/src/forge/_generated/workflowSubscriptions.ts +3 -3
- package/src/forge/cli/commands.ts +861 -861
- package/src/forge/cli/deps.ts +178 -11
- package/src/forge/cli/dev.ts +32 -5
- package/src/forge/cli/index.ts +7 -7
- package/src/forge/cli/main.ts +54 -54
- package/src/forge/cli/new.ts +29 -1
- package/src/forge/cli/output.ts +97 -97
- package/src/forge/cli/parse.ts +679 -673
- package/src/forge/cli/version.ts +1 -1
- package/src/forge/compiler/agent-contract/build.ts +28 -0
- package/src/forge/compiler/agent-contract/types.ts +16 -0
- package/src/forge/compiler/app-graph/build.ts +112 -112
- package/src/forge/compiler/app-graph/classify.ts +10 -10
- package/src/forge/compiler/app-graph/dup-symbol.ts +29 -29
- package/src/forge/compiler/app-graph/extract.ts +123 -123
- package/src/forge/compiler/app-graph/forge-apis.ts +29 -29
- package/src/forge/compiler/app-graph/index.ts +11 -11
- package/src/forge/compiler/app-graph/module-graph.ts +316 -316
- package/src/forge/compiler/app-graph/parser.ts +119 -119
- package/src/forge/compiler/app-graph/symbols.ts +48 -48
- package/src/forge/compiler/app-graph/tsconfig-hash.ts +62 -62
- package/src/forge/compiler/app-graph/types.ts +43 -43
- package/src/forge/compiler/app-graph/versions.ts +14 -14
- package/src/forge/compiler/cache/index.ts +17 -17
- package/src/forge/compiler/cache/key.ts +46 -46
- package/src/forge/compiler/cache/scheduler.ts +72 -72
- package/src/forge/compiler/cache/store.ts +78 -78
- package/src/forge/compiler/classifier/capabilities.ts +78 -78
- package/src/forge/compiler/classifier/classify.ts +113 -113
- package/src/forge/compiler/classifier/contexts.ts +188 -188
- package/src/forge/compiler/classifier/index.ts +18 -18
- package/src/forge/compiler/classifier/runtime-matrix.ts +45 -45
- package/src/forge/compiler/classifier/secrets.ts +41 -41
- package/src/forge/compiler/classifier/signals.ts +129 -129
- package/src/forge/compiler/diagnostics/codes.ts +125 -120
- package/src/forge/compiler/diagnostics/create.ts +87 -87
- package/src/forge/compiler/diagnostics/index.ts +41 -41
- package/src/forge/compiler/emitter/artifact-kind.ts +14 -14
- package/src/forge/compiler/emitter/barrel.ts +38 -38
- package/src/forge/compiler/emitter/constants.ts +7 -7
- package/src/forge/compiler/emitter/emit.ts +234 -237
- package/src/forge/compiler/emitter/index.ts +24 -24
- package/src/forge/compiler/emitter/lock.ts +61 -61
- package/src/forge/compiler/emitter/render.ts +73 -73
- package/src/forge/compiler/guards/artifacts.ts +96 -96
- package/src/forge/compiler/guards/check-import-guards.ts +106 -106
- package/src/forge/compiler/guards/index.ts +11 -11
- package/src/forge/compiler/guards/propagate-contexts.ts +57 -57
- package/src/forge/compiler/index.ts +17 -17
- package/src/forge/compiler/integration/add.ts +493 -493
- package/src/forge/compiler/integration/index.ts +17 -17
- package/src/forge/compiler/integration/plan.ts +279 -279
- package/src/forge/compiler/integration/render.ts +189 -189
- package/src/forge/compiler/integration/snapshot.ts +52 -52
- package/src/forge/compiler/orchestrator/discover.ts +214 -214
- package/src/forge/compiler/orchestrator/guards.ts +5 -5
- package/src/forge/compiler/orchestrator/index.ts +27 -27
- package/src/forge/compiler/orchestrator/manifest.ts +69 -69
- package/src/forge/compiler/orchestrator/orphans.ts +51 -51
- package/src/forge/compiler/orchestrator/plan.ts +804 -804
- package/src/forge/compiler/orchestrator/run.ts +178 -178
- package/src/forge/compiler/orchestrator/serialize.ts +859 -859
- package/src/forge/compiler/orchestrator/types.ts +23 -23
- package/src/forge/compiler/orchestrator/verify.ts +35 -35
- package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -33
- package/src/forge/compiler/package-graph/checksum.ts +107 -97
- package/src/forge/compiler/package-graph/compiler.ts +444 -363
- package/src/forge/compiler/package-graph/constants.ts +4 -4
- package/src/forge/compiler/package-graph/exports-discovery.ts +91 -84
- package/src/forge/compiler/package-graph/extract-dts.ts +32 -32
- package/src/forge/compiler/package-graph/index.ts +24 -24
- package/src/forge/compiler/package-graph/jsdoc.ts +50 -50
- package/src/forge/compiler/package-graph/oracle.ts +326 -0
- package/src/forge/compiler/package-graph/read-file.ts +21 -21
- package/src/forge/compiler/package-graph/resolve.ts +131 -127
- package/src/forge/compiler/package-manager/adapter.ts +232 -232
- package/src/forge/compiler/package-manager/commands.ts +47 -47
- package/src/forge/compiler/package-manager/detect.ts +65 -65
- package/src/forge/compiler/package-manager/executor.ts +29 -29
- package/src/forge/compiler/package-manager/index.ts +22 -22
- package/src/forge/compiler/package-manager/parse-spec.ts +16 -16
- package/src/forge/compiler/package-manager/version.ts +20 -20
- package/src/forge/compiler/primitives/compare.ts +26 -26
- package/src/forge/compiler/primitives/hash.ts +42 -33
- package/src/forge/compiler/primitives/header.ts +43 -43
- package/src/forge/compiler/primitives/index.ts +45 -45
- package/src/forge/compiler/primitives/paths.ts +24 -24
- package/src/forge/compiler/primitives/serialize.ts +66 -66
- package/src/forge/compiler/primitives/sort.ts +87 -87
- package/src/forge/compiler/recipes/definitions.ts +269 -269
- package/src/forge/compiler/recipes/helpers.ts +37 -37
- package/src/forge/compiler/recipes/index.ts +21 -21
- package/src/forge/compiler/recipes/registry.ts +87 -87
- package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -26
- package/src/forge/compiler/sandbox/backends/child.ts +123 -123
- package/src/forge/compiler/sandbox/backends/docker.ts +173 -173
- package/src/forge/compiler/sandbox/index.ts +51 -51
- package/src/forge/compiler/sandbox/inspect.ts +143 -143
- package/src/forge/compiler/sandbox/inspector-entry.ts +115 -115
- package/src/forge/compiler/sandbox/limits.ts +31 -31
- package/src/forge/compiler/sandbox/scrub-env.ts +60 -60
- package/src/forge/compiler/sandbox/secret-scan.ts +54 -54
- package/src/forge/compiler/sandbox/serialize.ts +106 -106
- package/src/forge/compiler/sandbox/types.ts +7 -7
- package/src/forge/compiler/types/app-graph.ts +71 -71
- package/src/forge/compiler/types/capability.ts +29 -29
- package/src/forge/compiler/types/classification.ts +9 -9
- package/src/forge/compiler/types/cli.ts +85 -85
- package/src/forge/compiler/types/diagnostic.ts +2 -2
- package/src/forge/compiler/types/emit.ts +25 -25
- package/src/forge/compiler/types/import-guards.ts +19 -19
- package/src/forge/compiler/types/index.ts +98 -98
- package/src/forge/compiler/types/integration.ts +25 -25
- package/src/forge/compiler/types/json.ts +3 -3
- package/src/forge/compiler/types/lock.ts +37 -37
- package/src/forge/compiler/types/package-graph.ts +122 -77
- package/src/forge/compiler/types/runtime-matrix.ts +16 -16
- package/src/forge/compiler/types/runtime.ts +30 -30
- package/src/forge/compiler/types/sandbox.ts +24 -24
- package/src/forge/dev/server.ts +16 -2
- package/src/forge/refactor/index.ts +10 -2
- package/src/forge/refactor/runtime-rename.ts +598 -0
- package/src/forge/runtime/executor.ts +3 -2
- package/src/forge/runtime/live/live-query-runner.ts +2 -1
- package/src/forge/runtime/outbox/process.ts +2 -1
- package/src/forge/runtime/query/run-query.ts +2 -1
- package/src/forge/runtime/runner/run-entry.ts +2 -1
- package/src/forge/runtime/telemetry/sinks/posthog.ts +4 -5
- package/src/forge/runtime/telemetry/sinks/sentry.ts +4 -5
- package/src/forge/runtime/workflows/resolve-step.ts +2 -1
- package/src/forge/version.ts +3 -0
- package/templates/b2b-support-web/src/actions/captureTicketCreated.ts +7 -2
- package/templates/b2b-support-web/src/commands/closeTicket.ts +6 -1
- package/templates/b2b-support-web/src/commands/createTicket.ts +8 -2
- package/templates/b2b-support-web/src/queries/getTicket.ts +8 -1
- package/templates/b2b-support-web/web/components/CreateTicketForm.tsx +1 -2
- package/templates/b2b-support-web/web/components/PolicyDeniedDemo.tsx +1 -2
- package/templates/b2b-support-web/web/components/TicketList.tsx +1 -2
- package/templates/b2b-support-web/web/components/TraceDetails.tsx +1 -1
- package/templates/b2b-support-web/web/lib/forge.ts +1 -0
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import type { ForgeLock, ForgeLockEntry } from "../types/lock.ts";
|
|
2
|
-
import type { SecretRequirement } from "../types/capability.ts";
|
|
3
|
-
import {
|
|
4
|
-
compareBytes,
|
|
5
|
-
serializeCanonical,
|
|
6
|
-
stableSortByPath,
|
|
7
|
-
stableSortStrings,
|
|
8
|
-
} from "../primitives/index.ts";
|
|
9
|
-
|
|
10
|
-
function compareLockEntries(a: ForgeLockEntry, b: ForgeLockEntry): number {
|
|
11
|
-
return compareBytes(a.name, b.name);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function compareSecrets(a: SecretRequirement, b: SecretRequirement): number {
|
|
15
|
-
return compareBytes(a.envVar, b.envVar);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function stableSortLockEntries(entries: ForgeLockEntry[]): ForgeLockEntry[] {
|
|
19
|
-
return [...entries].sort(compareLockEntries);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function stableSortSecrets(secrets: SecretRequirement[]): SecretRequirement[] {
|
|
23
|
-
return [...secrets].sort(compareSecrets);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function canonicalizeLockEntry(entry: ForgeLockEntry): ForgeLockEntry {
|
|
27
|
-
return {
|
|
28
|
-
name: entry.name,
|
|
29
|
-
version: entry.version,
|
|
30
|
-
...(entry.recipeVersion !== undefined
|
|
31
|
-
? { recipeVersion: entry.recipeVersion }
|
|
32
|
-
: {}),
|
|
1
|
+
import type { ForgeLock, ForgeLockEntry } from "../types/lock.ts";
|
|
2
|
+
import type { SecretRequirement } from "../types/capability.ts";
|
|
3
|
+
import {
|
|
4
|
+
compareBytes,
|
|
5
|
+
serializeCanonical,
|
|
6
|
+
stableSortByPath,
|
|
7
|
+
stableSortStrings,
|
|
8
|
+
} from "../primitives/index.ts";
|
|
9
|
+
|
|
10
|
+
function compareLockEntries(a: ForgeLockEntry, b: ForgeLockEntry): number {
|
|
11
|
+
return compareBytes(a.name, b.name);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function compareSecrets(a: SecretRequirement, b: SecretRequirement): number {
|
|
15
|
+
return compareBytes(a.envVar, b.envVar);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function stableSortLockEntries(entries: ForgeLockEntry[]): ForgeLockEntry[] {
|
|
19
|
+
return [...entries].sort(compareLockEntries);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function stableSortSecrets(secrets: SecretRequirement[]): SecretRequirement[] {
|
|
23
|
+
return [...secrets].sort(compareSecrets);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function canonicalizeLockEntry(entry: ForgeLockEntry): ForgeLockEntry {
|
|
27
|
+
return {
|
|
28
|
+
name: entry.name,
|
|
29
|
+
version: entry.version,
|
|
30
|
+
...(entry.recipeVersion !== undefined
|
|
31
|
+
? { recipeVersion: entry.recipeVersion }
|
|
32
|
+
: {}),
|
|
33
33
|
runtimeContexts: stableSortStrings([...entry.runtimeContexts]) as ForgeLockEntry["runtimeContexts"],
|
|
34
|
-
capabilities: {
|
|
35
|
-
...entry.capabilities,
|
|
36
|
-
secrets: stableSortSecrets([...entry.capabilities.secrets]),
|
|
37
|
-
},
|
|
38
|
-
secrets: stableSortSecrets([...entry.secrets]),
|
|
39
|
-
generatedFiles: stableSortByPath([...entry.generatedFiles]),
|
|
40
|
-
contentChecksum: entry.contentChecksum,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Deterministic forge.lock serialization (no deterministic header).
|
|
46
|
-
*/
|
|
47
|
-
export function serializeForgeLock(lock: ForgeLock): string {
|
|
48
|
-
const canonical: ForgeLock = {
|
|
49
|
-
schemaVersion: lock.schemaVersion,
|
|
50
|
-
generatorVersion: lock.generatorVersion,
|
|
51
|
-
analyzerVersion: lock.analyzerVersion,
|
|
52
|
-
inputHash: lock.inputHash,
|
|
53
|
-
lockfileHash: lock.lockfileHash,
|
|
54
|
-
packageManager: lock.packageManager,
|
|
55
|
-
...(lock.recipeVersion !== undefined
|
|
56
|
-
? { recipeVersion: lock.recipeVersion }
|
|
57
|
-
: {}),
|
|
58
|
-
packages: stableSortLockEntries(lock.packages).map(canonicalizeLockEntry),
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return serializeCanonical(canonical);
|
|
62
|
-
}
|
|
34
|
+
capabilities: {
|
|
35
|
+
...entry.capabilities,
|
|
36
|
+
secrets: stableSortSecrets([...entry.capabilities.secrets]),
|
|
37
|
+
},
|
|
38
|
+
secrets: stableSortSecrets([...entry.secrets]),
|
|
39
|
+
generatedFiles: stableSortByPath([...entry.generatedFiles]),
|
|
40
|
+
contentChecksum: entry.contentChecksum,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Deterministic forge.lock serialization (no deterministic header).
|
|
46
|
+
*/
|
|
47
|
+
export function serializeForgeLock(lock: ForgeLock): string {
|
|
48
|
+
const canonical: ForgeLock = {
|
|
49
|
+
schemaVersion: lock.schemaVersion,
|
|
50
|
+
generatorVersion: lock.generatorVersion,
|
|
51
|
+
analyzerVersion: lock.analyzerVersion,
|
|
52
|
+
inputHash: lock.inputHash,
|
|
53
|
+
lockfileHash: lock.lockfileHash,
|
|
54
|
+
packageManager: lock.packageManager,
|
|
55
|
+
...(lock.recipeVersion !== undefined
|
|
56
|
+
? { recipeVersion: lock.recipeVersion }
|
|
57
|
+
: {}),
|
|
58
|
+
packages: stableSortLockEntries(lock.packages).map(canonicalizeLockEntry),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return serializeCanonical(canonical);
|
|
62
|
+
}
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import type { EmitFile } from "../types/emit.ts";
|
|
2
|
-
import {
|
|
3
|
-
hashStable,
|
|
4
|
-
prependDeterministicHeader,
|
|
5
|
-
normalizeNewlines,
|
|
6
|
-
serializeCanonical,
|
|
7
|
-
} from "../primitives/index.ts";
|
|
8
|
-
import { detectArtifactKind } from "./artifact-kind.ts";
|
|
9
|
-
|
|
10
|
-
export interface RenderContext {
|
|
11
|
-
generatorVersion: string;
|
|
12
|
-
inputHash: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function renderJsonBody(content: string): string {
|
|
16
|
-
try {
|
|
17
|
-
const parsed: unknown = JSON.parse(content);
|
|
18
|
-
return serializeCanonical(parsed);
|
|
19
|
-
} catch {
|
|
20
|
-
return normalizeNewlines(content);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function renderTypeScriptBody(content: string): string {
|
|
25
|
-
return normalizeNewlines(content);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function renderMarkdownBody(content: string): string {
|
|
29
|
-
return normalizeNewlines(content);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function renderTextBody(content: string): string {
|
|
33
|
-
return normalizeNewlines(content);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Normalize file body bytes by artifact kind (no deterministic header).
|
|
38
|
-
*/
|
|
39
|
-
export function renderBody(file: EmitFile): string {
|
|
40
|
-
const kind = detectArtifactKind(file.path);
|
|
41
|
-
|
|
42
|
-
switch (kind) {
|
|
43
|
-
case "json":
|
|
44
|
-
if (file.canonical) {
|
|
45
|
-
return normalizeNewlines(file.content);
|
|
46
|
-
}
|
|
47
|
-
return renderJsonBody(file.content);
|
|
48
|
-
case "typescript":
|
|
49
|
-
return renderTypeScriptBody(file.content);
|
|
50
|
-
case "markdown":
|
|
51
|
-
return renderMarkdownBody(file.content);
|
|
52
|
-
default:
|
|
53
|
-
return renderTextBody(file.content);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Pure render: same EmitFile + context → same bytes (header included).
|
|
59
|
-
*/
|
|
60
|
-
export function render(file: EmitFile, context: RenderContext): string {
|
|
61
|
-
const body = renderBody(file);
|
|
62
|
-
|
|
63
|
-
if (file.contentHash !== hashStable(body)) {
|
|
64
|
-
throw new Error(
|
|
65
|
-
`EmitFile contentHash mismatch for ${file.path}: expected ${hashStable(body)}, got ${file.contentHash}`,
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return prependDeterministicHeader(body, {
|
|
70
|
-
generatorVersion: context.generatorVersion,
|
|
71
|
-
inputHash: context.inputHash,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
1
|
+
import type { EmitFile } from "../types/emit.ts";
|
|
2
|
+
import {
|
|
3
|
+
hashStable,
|
|
4
|
+
prependDeterministicHeader,
|
|
5
|
+
normalizeNewlines,
|
|
6
|
+
serializeCanonical,
|
|
7
|
+
} from "../primitives/index.ts";
|
|
8
|
+
import { detectArtifactKind } from "./artifact-kind.ts";
|
|
9
|
+
|
|
10
|
+
export interface RenderContext {
|
|
11
|
+
generatorVersion: string;
|
|
12
|
+
inputHash: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function renderJsonBody(content: string): string {
|
|
16
|
+
try {
|
|
17
|
+
const parsed: unknown = JSON.parse(content);
|
|
18
|
+
return serializeCanonical(parsed);
|
|
19
|
+
} catch {
|
|
20
|
+
return normalizeNewlines(content);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function renderTypeScriptBody(content: string): string {
|
|
25
|
+
return normalizeNewlines(content);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function renderMarkdownBody(content: string): string {
|
|
29
|
+
return normalizeNewlines(content);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function renderTextBody(content: string): string {
|
|
33
|
+
return normalizeNewlines(content);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Normalize file body bytes by artifact kind (no deterministic header).
|
|
38
|
+
*/
|
|
39
|
+
export function renderBody(file: EmitFile): string {
|
|
40
|
+
const kind = detectArtifactKind(file.path);
|
|
41
|
+
|
|
42
|
+
switch (kind) {
|
|
43
|
+
case "json":
|
|
44
|
+
if (file.canonical) {
|
|
45
|
+
return normalizeNewlines(file.content);
|
|
46
|
+
}
|
|
47
|
+
return renderJsonBody(file.content);
|
|
48
|
+
case "typescript":
|
|
49
|
+
return renderTypeScriptBody(file.content);
|
|
50
|
+
case "markdown":
|
|
51
|
+
return renderMarkdownBody(file.content);
|
|
52
|
+
default:
|
|
53
|
+
return renderTextBody(file.content);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Pure render: same EmitFile + context → same bytes (header included).
|
|
59
|
+
*/
|
|
60
|
+
export function render(file: EmitFile, context: RenderContext): string {
|
|
61
|
+
const body = renderBody(file);
|
|
62
|
+
|
|
63
|
+
if (file.contentHash !== hashStable(body)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`EmitFile contentHash mismatch for ${file.path}: expected ${hashStable(body)}, got ${file.contentHash}`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return prependDeterministicHeader(body, {
|
|
70
|
+
generatorVersion: context.generatorVersion,
|
|
71
|
+
inputHash: context.inputHash,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
import { GENERATED_DIR } from "../emitter/constants.ts";
|
|
2
|
-
import { hashStable, serializeCanonical } from "../primitives/index.ts";
|
|
3
|
-
import type { EmitFile } from "../types/emit.ts";
|
|
4
|
-
import type { ModuleGraph } from "../types/app-graph.ts";
|
|
5
|
-
import type { ImportGuardsArtifact } from "../types/import-guards.ts";
|
|
6
|
-
import type { RuntimeMatrix } from "../types/runtime-matrix.ts";
|
|
7
|
-
import { propagateContexts } from "./propagate-contexts.ts";
|
|
8
|
-
|
|
9
|
-
export function buildImportGuardsArtifact(
|
|
10
|
-
matrix: RuntimeMatrix,
|
|
11
|
-
moduleGraph?: ModuleGraph,
|
|
12
|
-
): ImportGuardsArtifact {
|
|
13
|
-
const entries = matrix.entries.map((entry) => ({
|
|
14
|
-
packageName: entry.packageName,
|
|
15
|
-
alias: entry.alias,
|
|
16
|
-
compatible: [...entry.compatible],
|
|
17
|
-
incompatible: [...entry.incompatible],
|
|
18
|
-
rationale: { ...entry.rationale },
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
let moduleContexts: ImportGuardsArtifact["moduleContexts"] = [];
|
|
22
|
-
if (moduleGraph) {
|
|
23
|
-
propagateContexts(moduleGraph);
|
|
24
|
-
moduleContexts = moduleGraph.nodes
|
|
25
|
-
.filter((node) => node.effectiveContexts.length > 0)
|
|
26
|
-
.map((node) => ({
|
|
27
|
-
file: node.file,
|
|
28
|
-
effectiveContexts: [...node.effectiveContexts],
|
|
29
|
-
}))
|
|
30
|
-
.sort((a, b) => (a.file < b.file ? -1 : a.file > b.file ? 1 : 0));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
schemaVersion: matrix.schemaVersion,
|
|
35
|
-
entries,
|
|
36
|
-
moduleContexts,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function renderRuntimeMatrixTs(matrix: RuntimeMatrix): string {
|
|
41
|
-
return `export const runtimeMatrix = ${serializeCanonical(matrix).trim()} as const;\n`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function renderImportGuardsTs(artifact: ImportGuardsArtifact): string {
|
|
45
|
-
return `export const importGuards = ${serializeCanonical(artifact).trim()} as const;\n`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function buildRuntimeMatrixEmitFiles(matrix: RuntimeMatrix): EmitFile[] {
|
|
49
|
-
const jsonBody = serializeCanonical(matrix);
|
|
50
|
-
const tsBody = renderRuntimeMatrixTs(matrix);
|
|
51
|
-
|
|
52
|
-
return [
|
|
53
|
-
{
|
|
54
|
-
path: `${GENERATED_DIR}/runtimeMatrix.json`,
|
|
55
|
-
content: jsonBody,
|
|
56
|
-
contentHash: hashStable(jsonBody),
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
path: `${GENERATED_DIR}/runtimeMatrix.ts`,
|
|
60
|
-
content: tsBody,
|
|
61
|
-
contentHash: hashStable(tsBody),
|
|
62
|
-
},
|
|
63
|
-
];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function buildImportGuardsEmitFiles(
|
|
67
|
-
matrix: RuntimeMatrix,
|
|
68
|
-
moduleGraph?: ModuleGraph,
|
|
69
|
-
): EmitFile[] {
|
|
70
|
-
const artifact = buildImportGuardsArtifact(matrix, moduleGraph);
|
|
71
|
-
const jsonBody = serializeCanonical(artifact);
|
|
72
|
-
const tsBody = renderImportGuardsTs(artifact);
|
|
73
|
-
|
|
74
|
-
return [
|
|
75
|
-
{
|
|
76
|
-
path: `${GENERATED_DIR}/importGuards.json`,
|
|
77
|
-
content: jsonBody,
|
|
78
|
-
contentHash: hashStable(jsonBody),
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
path: `${GENERATED_DIR}/importGuards.ts`,
|
|
82
|
-
content: tsBody,
|
|
83
|
-
contentHash: hashStable(tsBody),
|
|
84
|
-
},
|
|
85
|
-
];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function buildGuardArtifactEmitFiles(
|
|
89
|
-
matrix: RuntimeMatrix,
|
|
90
|
-
moduleGraph?: ModuleGraph,
|
|
91
|
-
): EmitFile[] {
|
|
92
|
-
return [
|
|
93
|
-
...buildRuntimeMatrixEmitFiles(matrix),
|
|
94
|
-
...buildImportGuardsEmitFiles(matrix, moduleGraph),
|
|
95
|
-
];
|
|
96
|
-
}
|
|
1
|
+
import { GENERATED_DIR } from "../emitter/constants.ts";
|
|
2
|
+
import { hashStable, serializeCanonical } from "../primitives/index.ts";
|
|
3
|
+
import type { EmitFile } from "../types/emit.ts";
|
|
4
|
+
import type { ModuleGraph } from "../types/app-graph.ts";
|
|
5
|
+
import type { ImportGuardsArtifact } from "../types/import-guards.ts";
|
|
6
|
+
import type { RuntimeMatrix } from "../types/runtime-matrix.ts";
|
|
7
|
+
import { propagateContexts } from "./propagate-contexts.ts";
|
|
8
|
+
|
|
9
|
+
export function buildImportGuardsArtifact(
|
|
10
|
+
matrix: RuntimeMatrix,
|
|
11
|
+
moduleGraph?: ModuleGraph,
|
|
12
|
+
): ImportGuardsArtifact {
|
|
13
|
+
const entries = matrix.entries.map((entry) => ({
|
|
14
|
+
packageName: entry.packageName,
|
|
15
|
+
alias: entry.alias,
|
|
16
|
+
compatible: [...entry.compatible],
|
|
17
|
+
incompatible: [...entry.incompatible],
|
|
18
|
+
rationale: { ...entry.rationale },
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
let moduleContexts: ImportGuardsArtifact["moduleContexts"] = [];
|
|
22
|
+
if (moduleGraph) {
|
|
23
|
+
propagateContexts(moduleGraph);
|
|
24
|
+
moduleContexts = moduleGraph.nodes
|
|
25
|
+
.filter((node) => node.effectiveContexts.length > 0)
|
|
26
|
+
.map((node) => ({
|
|
27
|
+
file: node.file,
|
|
28
|
+
effectiveContexts: [...node.effectiveContexts],
|
|
29
|
+
}))
|
|
30
|
+
.sort((a, b) => (a.file < b.file ? -1 : a.file > b.file ? 1 : 0));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
schemaVersion: matrix.schemaVersion,
|
|
35
|
+
entries,
|
|
36
|
+
moduleContexts,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderRuntimeMatrixTs(matrix: RuntimeMatrix): string {
|
|
41
|
+
return `export const runtimeMatrix = ${serializeCanonical(matrix).trim()} as const;\n`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function renderImportGuardsTs(artifact: ImportGuardsArtifact): string {
|
|
45
|
+
return `export const importGuards = ${serializeCanonical(artifact).trim()} as const;\n`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function buildRuntimeMatrixEmitFiles(matrix: RuntimeMatrix): EmitFile[] {
|
|
49
|
+
const jsonBody = serializeCanonical(matrix);
|
|
50
|
+
const tsBody = renderRuntimeMatrixTs(matrix);
|
|
51
|
+
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
path: `${GENERATED_DIR}/runtimeMatrix.json`,
|
|
55
|
+
content: jsonBody,
|
|
56
|
+
contentHash: hashStable(jsonBody),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
path: `${GENERATED_DIR}/runtimeMatrix.ts`,
|
|
60
|
+
content: tsBody,
|
|
61
|
+
contentHash: hashStable(tsBody),
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function buildImportGuardsEmitFiles(
|
|
67
|
+
matrix: RuntimeMatrix,
|
|
68
|
+
moduleGraph?: ModuleGraph,
|
|
69
|
+
): EmitFile[] {
|
|
70
|
+
const artifact = buildImportGuardsArtifact(matrix, moduleGraph);
|
|
71
|
+
const jsonBody = serializeCanonical(artifact);
|
|
72
|
+
const tsBody = renderImportGuardsTs(artifact);
|
|
73
|
+
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
path: `${GENERATED_DIR}/importGuards.json`,
|
|
77
|
+
content: jsonBody,
|
|
78
|
+
contentHash: hashStable(jsonBody),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
path: `${GENERATED_DIR}/importGuards.ts`,
|
|
82
|
+
content: tsBody,
|
|
83
|
+
contentHash: hashStable(tsBody),
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function buildGuardArtifactEmitFiles(
|
|
89
|
+
matrix: RuntimeMatrix,
|
|
90
|
+
moduleGraph?: ModuleGraph,
|
|
91
|
+
): EmitFile[] {
|
|
92
|
+
return [
|
|
93
|
+
...buildRuntimeMatrixEmitFiles(matrix),
|
|
94
|
+
...buildImportGuardsEmitFiles(matrix, moduleGraph),
|
|
95
|
+
];
|
|
96
|
+
}
|
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import { lookupMatrixEntry } from "../classifier/runtime-matrix.ts";
|
|
2
|
-
import { forgeGuardViolation } from "../diagnostics/create.ts";
|
|
3
|
-
import type { ModuleGraph } from "../types/app-graph.ts";
|
|
4
|
-
import type { Diagnostic } from "../types/diagnostic.ts";
|
|
5
|
-
import type { RuntimeContext } from "../types/runtime.ts";
|
|
6
|
-
import type { RuntimeMatrix } from "../types/runtime-matrix.ts";
|
|
7
|
-
import { comparePaths } from "../primitives/paths.ts";
|
|
8
|
-
import { compareBytes } from "../primitives/compare.ts";
|
|
9
|
-
import { propagateContexts } from "./propagate-contexts.ts";
|
|
10
|
-
|
|
11
|
-
function compareDiagnostics(a: Diagnostic, b: Diagnostic): number {
|
|
12
|
-
let cmp = comparePaths(a.file ?? "", b.file ?? "");
|
|
13
|
-
if (cmp !== 0) {
|
|
14
|
-
return cmp;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
cmp = (a.span?.start ?? 0) - (b.span?.start ?? 0);
|
|
18
|
-
if (cmp !== 0) {
|
|
19
|
-
return cmp;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const aPackage = extractPackageName(a.message);
|
|
23
|
-
const bPackage = extractPackageName(b.message);
|
|
24
|
-
cmp = compareBytes(aPackage, bPackage);
|
|
25
|
-
if (cmp !== 0) {
|
|
26
|
-
return cmp;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const aContext = extractContext(a.message);
|
|
30
|
-
const bContext = extractContext(b.message);
|
|
31
|
-
return compareBytes(aContext, bContext);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function extractPackageName(message: string): string {
|
|
35
|
-
const match = /^'([^']+)' is not allowed/.exec(message);
|
|
36
|
-
return match?.[1] ?? "";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function extractContext(message: string): string {
|
|
40
|
-
const match = /'([^']+)' context/.exec(message);
|
|
41
|
-
return match?.[1] ?? "";
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Evaluate package imports against the runtime matrix after propagating effective contexts.
|
|
46
|
-
*/
|
|
47
|
-
export function checkImportGuards(
|
|
48
|
-
moduleGraph: ModuleGraph,
|
|
49
|
-
matrix: RuntimeMatrix,
|
|
50
|
-
): Diagnostic[] {
|
|
51
|
-
propagateContexts(moduleGraph);
|
|
52
|
-
|
|
53
|
-
const diagnostics: Diagnostic[] = [];
|
|
54
|
-
const recorded = new Set<string>();
|
|
55
|
-
|
|
56
|
-
for (const node of moduleGraph.nodes) {
|
|
57
|
-
if (node.effectiveContexts.length === 0) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
for (const imp of node.directPackageImports) {
|
|
62
|
-
const entry = lookupMatrixEntry(matrix, imp.packageName);
|
|
63
|
-
if (entry == null) {
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
for (const context of node.effectiveContexts) {
|
|
68
|
-
if (!entry.compatible.includes(context)) {
|
|
69
|
-
const key = `${node.file}\0${imp.packageName}\0${context}\0${imp.span.start}`;
|
|
70
|
-
if (recorded.has(key)) {
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
recorded.add(key);
|
|
74
|
-
|
|
75
|
-
const rationale =
|
|
76
|
-
entry.rationale[context] ??
|
|
77
|
-
"package is incompatible with this runtime context";
|
|
78
|
-
diagnostics.push(
|
|
79
|
-
forgeGuardViolation(
|
|
80
|
-
imp.packageName,
|
|
81
|
-
context,
|
|
82
|
-
rationale,
|
|
83
|
-
node.file,
|
|
84
|
-
imp.span,
|
|
85
|
-
),
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
diagnostics.sort(compareDiagnostics);
|
|
93
|
-
return diagnostics;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function isContextViolating(
|
|
97
|
-
matrix: RuntimeMatrix,
|
|
98
|
-
packageName: string,
|
|
99
|
-
context: RuntimeContext,
|
|
100
|
-
): boolean {
|
|
101
|
-
const entry = lookupMatrixEntry(matrix, packageName);
|
|
102
|
-
if (entry == null) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
return !entry.compatible.includes(context);
|
|
106
|
-
}
|
|
1
|
+
import { lookupMatrixEntry } from "../classifier/runtime-matrix.ts";
|
|
2
|
+
import { forgeGuardViolation } from "../diagnostics/create.ts";
|
|
3
|
+
import type { ModuleGraph } from "../types/app-graph.ts";
|
|
4
|
+
import type { Diagnostic } from "../types/diagnostic.ts";
|
|
5
|
+
import type { RuntimeContext } from "../types/runtime.ts";
|
|
6
|
+
import type { RuntimeMatrix } from "../types/runtime-matrix.ts";
|
|
7
|
+
import { comparePaths } from "../primitives/paths.ts";
|
|
8
|
+
import { compareBytes } from "../primitives/compare.ts";
|
|
9
|
+
import { propagateContexts } from "./propagate-contexts.ts";
|
|
10
|
+
|
|
11
|
+
function compareDiagnostics(a: Diagnostic, b: Diagnostic): number {
|
|
12
|
+
let cmp = comparePaths(a.file ?? "", b.file ?? "");
|
|
13
|
+
if (cmp !== 0) {
|
|
14
|
+
return cmp;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
cmp = (a.span?.start ?? 0) - (b.span?.start ?? 0);
|
|
18
|
+
if (cmp !== 0) {
|
|
19
|
+
return cmp;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const aPackage = extractPackageName(a.message);
|
|
23
|
+
const bPackage = extractPackageName(b.message);
|
|
24
|
+
cmp = compareBytes(aPackage, bPackage);
|
|
25
|
+
if (cmp !== 0) {
|
|
26
|
+
return cmp;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const aContext = extractContext(a.message);
|
|
30
|
+
const bContext = extractContext(b.message);
|
|
31
|
+
return compareBytes(aContext, bContext);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function extractPackageName(message: string): string {
|
|
35
|
+
const match = /^'([^']+)' is not allowed/.exec(message);
|
|
36
|
+
return match?.[1] ?? "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function extractContext(message: string): string {
|
|
40
|
+
const match = /'([^']+)' context/.exec(message);
|
|
41
|
+
return match?.[1] ?? "";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Evaluate package imports against the runtime matrix after propagating effective contexts.
|
|
46
|
+
*/
|
|
47
|
+
export function checkImportGuards(
|
|
48
|
+
moduleGraph: ModuleGraph,
|
|
49
|
+
matrix: RuntimeMatrix,
|
|
50
|
+
): Diagnostic[] {
|
|
51
|
+
propagateContexts(moduleGraph);
|
|
52
|
+
|
|
53
|
+
const diagnostics: Diagnostic[] = [];
|
|
54
|
+
const recorded = new Set<string>();
|
|
55
|
+
|
|
56
|
+
for (const node of moduleGraph.nodes) {
|
|
57
|
+
if (node.effectiveContexts.length === 0) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const imp of node.directPackageImports) {
|
|
62
|
+
const entry = lookupMatrixEntry(matrix, imp.packageName);
|
|
63
|
+
if (entry == null) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const context of node.effectiveContexts) {
|
|
68
|
+
if (!entry.compatible.includes(context)) {
|
|
69
|
+
const key = `${node.file}\0${imp.packageName}\0${context}\0${imp.span.start}`;
|
|
70
|
+
if (recorded.has(key)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
recorded.add(key);
|
|
74
|
+
|
|
75
|
+
const rationale =
|
|
76
|
+
entry.rationale[context] ??
|
|
77
|
+
"package is incompatible with this runtime context";
|
|
78
|
+
diagnostics.push(
|
|
79
|
+
forgeGuardViolation(
|
|
80
|
+
imp.packageName,
|
|
81
|
+
context,
|
|
82
|
+
rationale,
|
|
83
|
+
node.file,
|
|
84
|
+
imp.span,
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
diagnostics.sort(compareDiagnostics);
|
|
93
|
+
return diagnostics;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isContextViolating(
|
|
97
|
+
matrix: RuntimeMatrix,
|
|
98
|
+
packageName: string,
|
|
99
|
+
context: RuntimeContext,
|
|
100
|
+
): boolean {
|
|
101
|
+
const entry = lookupMatrixEntry(matrix, packageName);
|
|
102
|
+
if (entry == null) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return !entry.compatible.includes(context);
|
|
106
|
+
}
|