semantifold 0.3.0 → 0.5.0
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/README.md +61 -15
- package/build/index.d.ts +52 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +60 -8
- package/build/src/artifact-path.d.ts +23 -1
- package/build/src/artifact-path.d.ts.map +1 -1
- package/build/src/artifact-path.js +45 -3
- package/build/src/artifacts.d.ts.map +1 -1
- package/build/src/artifacts.js +66 -1
- package/build/src/backends/android.d.ts +49 -0
- package/build/src/backends/android.d.ts.map +1 -0
- package/build/src/backends/android.js +1274 -0
- package/build/src/backends/c-validation.d.ts.map +1 -1
- package/build/src/backends/c-validation.js +7 -3
- package/build/src/backends/cpp-validation.d.ts.map +1 -1
- package/build/src/backends/cpp-validation.js +7 -3
- package/build/src/backends/csharp.js +7 -1
- package/build/src/backends/dart-runtime.d.ts +2 -0
- package/build/src/backends/dart-runtime.d.ts.map +1 -0
- package/build/src/backends/dart-runtime.js +41 -0
- package/build/src/backends/dart.d.ts +20 -0
- package/build/src/backends/dart.d.ts.map +1 -0
- package/build/src/backends/dart.js +321 -0
- package/build/src/backends/effects.d.ts +60 -0
- package/build/src/backends/effects.d.ts.map +1 -0
- package/build/src/backends/effects.js +746 -0
- package/build/src/backends/go.js +18 -4
- package/build/src/backends/identifiers.d.ts +36 -4
- package/build/src/backends/identifiers.d.ts.map +1 -1
- package/build/src/backends/identifiers.js +160 -10
- package/build/src/backends/index.d.ts.map +1 -1
- package/build/src/backends/index.js +27 -4
- package/build/src/backends/ios.d.ts +68 -0
- package/build/src/backends/ios.d.ts.map +1 -0
- package/build/src/backends/ios.js +1503 -0
- package/build/src/backends/java.d.ts.map +1 -1
- package/build/src/backends/java.js +429 -36
- package/build/src/backends/javascript.d.ts +6 -0
- package/build/src/backends/javascript.d.ts.map +1 -1
- package/build/src/backends/javascript.js +380 -24
- package/build/src/backends/kotlin-runtime.d.ts +3 -0
- package/build/src/backends/kotlin-runtime.d.ts.map +1 -0
- package/build/src/backends/kotlin-runtime.js +29 -0
- package/build/src/backends/kotlin.d.ts +33 -0
- package/build/src/backends/kotlin.d.ts.map +1 -0
- package/build/src/backends/kotlin.js +138 -0
- package/build/src/backends/native-validation.d.ts +2 -2
- package/build/src/backends/native-validation.d.ts.map +1 -1
- package/build/src/backends/native-validation.js +2 -2
- package/build/src/backends/ordered-expressions.d.ts.map +1 -1
- package/build/src/backends/ordered-expressions.js +39 -7
- package/build/src/backends/php-stdlib-support.d.ts +19 -0
- package/build/src/backends/php-stdlib-support.d.ts.map +1 -0
- package/build/src/backends/php-stdlib-support.js +227 -0
- package/build/src/backends/php.d.ts.map +1 -1
- package/build/src/backends/php.js +448 -33
- package/build/src/backends/program.d.ts +83 -0
- package/build/src/backends/program.d.ts.map +1 -0
- package/build/src/backends/program.js +1309 -0
- package/build/src/backends/python.js +7 -1
- package/build/src/backends/ruby.d.ts.map +1 -1
- package/build/src/backends/ruby.js +310 -24
- package/build/src/backends/rust-runtime.d.ts +7 -0
- package/build/src/backends/rust-runtime.d.ts.map +1 -0
- package/build/src/backends/rust-runtime.js +32 -0
- package/build/src/backends/rust-validation.d.ts +9 -0
- package/build/src/backends/rust-validation.d.ts.map +1 -0
- package/build/src/backends/rust-validation.js +78 -0
- package/build/src/backends/rust.d.ts +24 -0
- package/build/src/backends/rust.d.ts.map +1 -0
- package/build/src/backends/rust.js +344 -0
- package/build/src/backends/scalars.d.ts +14 -6
- package/build/src/backends/scalars.d.ts.map +1 -1
- package/build/src/backends/scalars.js +167 -17
- package/build/src/backends/shared.d.ts +23 -4
- package/build/src/backends/shared.d.ts.map +1 -1
- package/build/src/backends/shared.js +2174 -62
- package/build/src/backends/stdlib-support.d.ts +14 -0
- package/build/src/backends/stdlib-support.d.ts.map +1 -0
- package/build/src/backends/stdlib-support.js +237 -0
- package/build/src/backends/swift-runtime.d.ts +3 -0
- package/build/src/backends/swift-runtime.d.ts.map +1 -0
- package/build/src/backends/swift-runtime.js +14 -0
- package/build/src/backends/swift.d.ts +8 -0
- package/build/src/backends/swift.d.ts.map +1 -0
- package/build/src/backends/swift.js +127 -0
- package/build/src/backends/typescript.d.ts.map +1 -1
- package/build/src/backends/typescript.js +344 -24
- package/build/src/backends/wasm.d.ts +43 -0
- package/build/src/backends/wasm.d.ts.map +1 -0
- package/build/src/backends/wasm.js +2164 -0
- package/build/src/backends/writer.d.ts +255 -4
- package/build/src/backends/writer.d.ts.map +1 -1
- package/build/src/backends/writer.js +491 -3
- package/build/src/diagnostic.d.ts +4 -3
- package/build/src/diagnostic.d.ts.map +1 -1
- package/build/src/diagnostic.js +5 -3
- package/build/src/frontends/c.d.ts.map +1 -1
- package/build/src/frontends/c.js +5 -3
- package/build/src/frontends/cpp.d.ts.map +1 -1
- package/build/src/frontends/cpp.js +5 -3
- package/build/src/frontends/csharp.d.ts.map +1 -1
- package/build/src/frontends/csharp.js +7 -3
- package/build/src/frontends/dart.d.ts +10 -0
- package/build/src/frontends/dart.d.ts.map +1 -0
- package/build/src/frontends/dart.js +913 -0
- package/build/src/frontends/index.d.ts +3 -1
- package/build/src/frontends/index.d.ts.map +1 -1
- package/build/src/frontends/index.js +15 -5
- package/build/src/frontends/java.d.ts +110 -1
- package/build/src/frontends/java.d.ts.map +1 -1
- package/build/src/frontends/java.js +1725 -70
- package/build/src/frontends/javascript-typescript.d.ts +69 -1
- package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
- package/build/src/frontends/javascript-typescript.js +1825 -93
- package/build/src/frontends/kotlin.d.ts +10 -0
- package/build/src/frontends/kotlin.d.ts.map +1 -0
- package/build/src/frontends/kotlin.js +685 -0
- package/build/src/frontends/php.d.ts +118 -1
- package/build/src/frontends/php.d.ts.map +1 -1
- package/build/src/frontends/php.js +1583 -76
- package/build/src/frontends/program.d.ts +74 -0
- package/build/src/frontends/program.d.ts.map +1 -0
- package/build/src/frontends/program.js +989 -0
- package/build/src/frontends/ruby.d.ts +68 -1
- package/build/src/frontends/ruby.d.ts.map +1 -1
- package/build/src/frontends/ruby.js +1446 -101
- package/build/src/frontends/rust-parser.d.ts +11 -0
- package/build/src/frontends/rust-parser.d.ts.map +1 -0
- package/build/src/frontends/rust-parser.js +15 -0
- package/build/src/frontends/rust.d.ts +14 -0
- package/build/src/frontends/rust.d.ts.map +1 -0
- package/build/src/frontends/rust.js +715 -0
- package/build/src/frontends/scalars.d.ts +10 -0
- package/build/src/frontends/scalars.d.ts.map +1 -1
- package/build/src/frontends/scalars.js +28 -2
- package/build/src/frontends/swift.d.ts +10 -0
- package/build/src/frontends/swift.d.ts.map +1 -0
- package/build/src/frontends/swift.js +860 -0
- package/build/src/frontends/types.d.ts +186 -0
- package/build/src/frontends/types.d.ts.map +1 -0
- package/build/src/frontends/types.js +634 -0
- package/build/src/language-registry.d.ts +46 -4
- package/build/src/language-registry.d.ts.map +1 -1
- package/build/src/language-registry.js +177 -13
- package/build/src/mapping.d.ts +2 -2
- package/build/src/mapping.d.ts.map +1 -1
- package/build/src/mapping.js +31 -10
- package/build/src/semantic/capabilities.d.ts +66 -0
- package/build/src/semantic/capabilities.d.ts.map +1 -0
- package/build/src/semantic/capabilities.js +649 -0
- package/build/src/semantic/effects.d.ts +26 -0
- package/build/src/semantic/effects.d.ts.map +1 -0
- package/build/src/semantic/effects.js +764 -0
- package/build/src/semantic/generics.d.ts +23 -0
- package/build/src/semantic/generics.d.ts.map +1 -0
- package/build/src/semantic/generics.js +61 -0
- package/build/src/semantic/lifetime.d.ts +37 -0
- package/build/src/semantic/lifetime.d.ts.map +1 -0
- package/build/src/semantic/lifetime.js +527 -0
- package/build/src/semantic/provenance.d.ts +9 -2
- package/build/src/semantic/provenance.d.ts.map +1 -1
- package/build/src/semantic/provenance.js +462 -20
- package/build/src/semantic/scalars.d.ts +11 -0
- package/build/src/semantic/scalars.d.ts.map +1 -1
- package/build/src/semantic/scalars.js +16 -1
- package/build/src/semantic/stdlib.d.ts +254 -0
- package/build/src/semantic/stdlib.d.ts.map +1 -0
- package/build/src/semantic/stdlib.js +880 -0
- package/build/src/semantic/types.d.ts +3108 -178
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +730 -15
- package/build/src/semantic/validate.d.ts +85 -5
- package/build/src/semantic/validate.d.ts.map +1 -1
- package/build/src/semantic/validate.js +2576 -98
- package/build/src/stdlib-facades.d.ts +304 -0
- package/build/src/stdlib-facades.d.ts.map +1 -0
- package/build/src/stdlib-facades.js +1167 -0
- package/build/src/stdlib-negotiation.d.ts +69 -0
- package/build/src/stdlib-negotiation.d.ts.map +1 -0
- package/build/src/stdlib-negotiation.js +403 -0
- package/build/src/stdlib-providers.d.ts +72 -0
- package/build/src/stdlib-providers.d.ts.map +1 -0
- package/build/src/stdlib-providers.js +339 -0
- package/build/src/toolchains.d.ts +55 -1
- package/build/src/toolchains.d.ts.map +1 -1
- package/build/src/toolchains.js +15 -4
- package/docs/android.md +79 -0
- package/docs/architecture.md +47 -13
- package/docs/dart.md +60 -0
- package/docs/goals.md +3 -3
- package/docs/ios.md +121 -0
- package/docs/kotlin.md +42 -0
- package/docs/language-support.md +238 -26
- package/docs/multi-file-modules.md +52 -0
- package/docs/parser-qualification.md +121 -8
- package/docs/plans/2026-09-05-standard-library-portability.md +10 -10
- package/docs/rust.md +88 -0
- package/docs/source-maps.md +17 -7
- package/docs/specification.md +5 -0
- package/docs/standard-library-portability.md +39 -8
- package/docs/swift.md +44 -0
- package/docs/testing.md +381 -4
- package/docs/webassembly.md +52 -0
- package/index.js +66 -8
- package/node_modules/semantifold-tree-sitter-legacy-internal/README.md +2 -2
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/LICENSE +21 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/README.md +45 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/binding.gyp +30 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding.cc +20 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding_test.js +9 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.d.ts +28 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.js +11 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/grammar.js +1630 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/package.json +64 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-arm64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-x64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-arm64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-x64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-arm64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-x64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/highlights.scm +159 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/injections.scm +9 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/tags.scm +60 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/grammar.json +9405 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/node-types.json +5399 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/parser.c +192569 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/scanner.c +393 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/alloc.h +54 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/array.h +290 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/parser.h +266 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter-rust.wasm +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter.json +53 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/package.json +3 -2
- package/node_modules/semantifold-tree-sitter-legacy-internal/src/c.js +5 -4
- package/package.json +5 -2
- package/src/artifact-path.js +47 -2
- package/src/artifacts.js +67 -0
- package/src/backends/android.js +1370 -0
- package/src/backends/c-validation.js +6 -1
- package/src/backends/cpp-validation.js +6 -1
- package/src/backends/csharp.js +3 -0
- package/src/backends/dart-runtime.js +41 -0
- package/src/backends/dart.js +326 -0
- package/src/backends/effects.js +705 -0
- package/src/backends/go.js +14 -2
- package/src/backends/identifiers.js +166 -9
- package/src/backends/index.js +27 -2
- package/src/backends/ios.js +1612 -0
- package/src/backends/java.js +454 -36
- package/src/backends/javascript.js +389 -23
- package/src/backends/kotlin-runtime.js +29 -0
- package/src/backends/kotlin.js +144 -0
- package/src/backends/native-validation.js +1 -1
- package/src/backends/ordered-expressions.js +40 -6
- package/src/backends/php-stdlib-support.js +239 -0
- package/src/backends/php.js +469 -32
- package/src/backends/program.js +1408 -0
- package/src/backends/python.js +3 -0
- package/src/backends/ruby.js +326 -23
- package/src/backends/rust-runtime.js +34 -0
- package/src/backends/rust-validation.js +75 -0
- package/src/backends/rust.js +335 -0
- package/src/backends/scalars.js +141 -16
- package/src/backends/shared.js +2314 -115
- package/src/backends/stdlib-support.js +234 -0
- package/src/backends/swift-runtime.js +14 -0
- package/src/backends/swift.js +132 -0
- package/src/backends/typescript.js +349 -23
- package/src/backends/wasm.js +2208 -0
- package/src/backends/writer.js +545 -2
- package/src/diagnostic.js +4 -2
- package/src/frontends/c.js +4 -2
- package/src/frontends/cpp.js +4 -2
- package/src/frontends/csharp.js +4 -2
- package/src/frontends/dart.js +963 -0
- package/src/frontends/index.js +14 -4
- package/src/frontends/java.js +1977 -69
- package/src/frontends/javascript-typescript.js +2046 -102
- package/src/frontends/kotlin.js +713 -0
- package/src/frontends/php.js +1725 -79
- package/src/frontends/program.js +1062 -0
- package/src/frontends/ruby.js +1624 -98
- package/src/frontends/rust-parser.js +18 -0
- package/src/frontends/rust.js +714 -0
- package/src/frontends/scalars.js +31 -1
- package/src/frontends/swift.js +893 -0
- package/src/frontends/types.js +750 -0
- package/src/language-registry.js +182 -12
- package/src/mapping.js +33 -9
- package/src/semantic/capabilities.js +671 -0
- package/src/semantic/effects.js +737 -0
- package/src/semantic/generics.js +58 -0
- package/src/semantic/lifetime.js +517 -0
- package/src/semantic/provenance.js +412 -19
- package/src/semantic/scalars.js +17 -0
- package/src/semantic/stdlib.js +921 -0
- package/src/semantic/types.js +810 -14
- package/src/semantic/validate.js +2934 -209
- package/src/stdlib-facades.js +1211 -0
- package/src/stdlib-negotiation.js +446 -0
- package/src/stdlib-providers.js +377 -0
- package/src/toolchains.js +16 -3
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {isDenseArray} from "./array.js"
|
|
4
|
+
import {SemantifoldDiagnostic} from "./diagnostic.js"
|
|
5
|
+
import {
|
|
6
|
+
compareStdlibVersions,
|
|
7
|
+
createStdlibContractRegistry,
|
|
8
|
+
intersectStdlibVersionRanges,
|
|
9
|
+
parseStdlibVersion,
|
|
10
|
+
parseStdlibVersionRange,
|
|
11
|
+
stdlibVersionSatisfies
|
|
12
|
+
} from "./semantic/stdlib.js"
|
|
13
|
+
import {stdlibProviderRegistry} from "./stdlib-providers.js"
|
|
14
|
+
|
|
15
|
+
/** @typedef {import("./semantic/stdlib.js").StdlibContractRegistry} StdlibContractRegistry */
|
|
16
|
+
/** @typedef {import("./stdlib-providers.js").StdlibProviderRecord} StdlibProviderRecord */
|
|
17
|
+
/** @typedef {import("./semantic/stdlib.js").VersionRange} VersionRange */
|
|
18
|
+
|
|
19
|
+
/** @type {Readonly<VersionRange>} */
|
|
20
|
+
const universalRange = Object.freeze({lower: /** @type {[number, number, number]} */ (Object.freeze([0, 0, 0])), upper: null})
|
|
21
|
+
const builtinContracts = createStdlibContractRegistry()
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef StdlibNegotiationRequirement
|
|
25
|
+
* @property {string} module - Canonical module identity.
|
|
26
|
+
* @property {string[]} operations - Required canonical operations.
|
|
27
|
+
* @property {string | undefined} [range] - Declared version range.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef StdlibNegotiationResult
|
|
32
|
+
* @property {string} target - Negotiated target language.
|
|
33
|
+
* @property {readonly {identity: string, operations: string[], version: string}[]} modules - Linked modules in identity order.
|
|
34
|
+
* @property {readonly {identity: string, target: string, module: string, version: string, operations: string[], nativeEntries: Readonly<Record<string, string>>, runtimeProfile: string}[]} providers - Selected providers in identity order.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Negotiates the complete transitive stdlib provider closure for one target.
|
|
39
|
+
* @param {{contracts?: StdlibContractRegistry, providers?: {providersFor(target: string, module: string, version: string): readonly StdlibProviderRecord[]}, requirements: StdlibNegotiationRequirement[], target: string}} input - Negotiation request.
|
|
40
|
+
* @returns {Readonly<StdlibNegotiationResult>} Frozen negotiation result.
|
|
41
|
+
*/
|
|
42
|
+
export function negotiateStdlibProviders({contracts = builtinContracts, providers = stdlibProviderRegistry, requirements, target}) {
|
|
43
|
+
if (!isDenseArray(requirements)) invalidRequirement("Stdlib negotiation requirements must be an ordered dense array.")
|
|
44
|
+
/** @type {Map<string, VersionRange>} */
|
|
45
|
+
const ranges = new Map()
|
|
46
|
+
/** @type {Map<string, string>} */
|
|
47
|
+
const rangeKeys = new Map()
|
|
48
|
+
/** @type {Map<string, Set<string>>} */
|
|
49
|
+
const usedOperations = new Map()
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Intersects one declared range into the per-module closure.
|
|
53
|
+
* @param {string} module - Canonical module identity.
|
|
54
|
+
* @param {VersionRange} range - Declared version range.
|
|
55
|
+
* @returns {boolean} Whether the combined range changed.
|
|
56
|
+
*/
|
|
57
|
+
function addRange(module, range) {
|
|
58
|
+
const current = ranges.get(module) ?? universalRange
|
|
59
|
+
const next = intersectStdlibVersionRanges(current, range)
|
|
60
|
+
|
|
61
|
+
if (next === null) throw new SemantifoldDiagnostic({
|
|
62
|
+
code: "STDLIB_VERSION_INCOMPATIBLE",
|
|
63
|
+
language: module,
|
|
64
|
+
message: `Canonical module '${module}' has no version satisfying every declared range.`
|
|
65
|
+
})
|
|
66
|
+
const key = rangeKey(next)
|
|
67
|
+
|
|
68
|
+
if (rangeKeys.get(module) == key) return false
|
|
69
|
+
ranges.set(module, next)
|
|
70
|
+
rangeKeys.set(module, key)
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Rejects a module identity absent from the contract registry.
|
|
76
|
+
* @param {string} module - Canonical module identity.
|
|
77
|
+
* @returns {void}
|
|
78
|
+
*/
|
|
79
|
+
function requireModule(module) {
|
|
80
|
+
if (!contracts.modules.some(({identity}) => identity == module)) {
|
|
81
|
+
throw new SemantifoldDiagnostic({
|
|
82
|
+
code: "STDLIB_MODULE_UNKNOWN",
|
|
83
|
+
language: module,
|
|
84
|
+
message: `Canonical module '${module}' is not registered.`
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const requirement of requirements) {
|
|
90
|
+
if (!isPlainObject(requirement)) invalidRequirement("Every stdlib negotiation requirement must be a plain object.")
|
|
91
|
+
const module = /** @type {string} */ (requirement.module)
|
|
92
|
+
const operations = /** @type {unknown} */ (requirement.operations)
|
|
93
|
+
|
|
94
|
+
if (typeof module != "string") {
|
|
95
|
+
throw new SemantifoldDiagnostic({code: "STDLIB_MODULE_UNKNOWN", language: String(module), message: "Canonical module identity is missing."})
|
|
96
|
+
}
|
|
97
|
+
if (!isDenseArray(operations) || !operations.every((operation) => typeof operation == "string")) {
|
|
98
|
+
invalidRequirement(`Requirement for module '${module}' declares invalid operations.`)
|
|
99
|
+
}
|
|
100
|
+
if (operations.length == 0) continue
|
|
101
|
+
requireModule(module)
|
|
102
|
+
for (const operation of /** @type {string[]} */ (operations)) {
|
|
103
|
+
const used = usedOperations.get(module) ?? new Set()
|
|
104
|
+
|
|
105
|
+
used.add(operation)
|
|
106
|
+
usedOperations.set(module, used)
|
|
107
|
+
}
|
|
108
|
+
if (requirement.range !== undefined) {
|
|
109
|
+
const range = parseStdlibVersionRange(requirement.range)
|
|
110
|
+
|
|
111
|
+
if (range === null) malformedRange(String(requirement.range))
|
|
112
|
+
addRange(module, range)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let changed = true
|
|
117
|
+
|
|
118
|
+
while (changed) {
|
|
119
|
+
changed = false
|
|
120
|
+
|
|
121
|
+
for (const module of [...usedOperations.keys()].sort()) {
|
|
122
|
+
const contract = resolveModuleVersion(contracts, module, ranges.get(module) ?? universalRange)
|
|
123
|
+
const declared = new Map(contract.operations.map(({dependencies, name}) => [name, dependencies]))
|
|
124
|
+
|
|
125
|
+
for (const dependency of contract.dependencies) {
|
|
126
|
+
requireModule(dependency.module)
|
|
127
|
+
if (addRange(dependency.module, asVersionRange(dependency.range))) changed = true
|
|
128
|
+
if (!usedOperations.has(dependency.module)) {
|
|
129
|
+
usedOperations.set(dependency.module, new Set())
|
|
130
|
+
changed = true
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
for (const operation of [.../** @type {Set<string>} */ (usedOperations.get(module))].sort()) {
|
|
135
|
+
const dependencies = declared.get(operation)
|
|
136
|
+
|
|
137
|
+
if (dependencies === undefined) undeclaredOperation(module, operation)
|
|
138
|
+
for (const dependency of dependencies) {
|
|
139
|
+
const {module: dependencyModule, operation: dependencyOperation, range} = dependency
|
|
140
|
+
|
|
141
|
+
requireModule(dependencyModule)
|
|
142
|
+
if (addRange(dependencyModule, asVersionRange(range))) changed = true
|
|
143
|
+
const used = usedOperations.get(dependencyModule) ?? new Set()
|
|
144
|
+
|
|
145
|
+
if (!used.has(dependencyOperation)) {
|
|
146
|
+
used.add(dependencyOperation)
|
|
147
|
+
usedOperations.set(dependencyModule, used)
|
|
148
|
+
changed = true
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** @type {Map<string, StdlibProviderRecord>} */
|
|
156
|
+
const selectedProviders = new Map()
|
|
157
|
+
let stable = false
|
|
158
|
+
|
|
159
|
+
while (!stable) {
|
|
160
|
+
stable = true
|
|
161
|
+
selectedProviders.clear()
|
|
162
|
+
|
|
163
|
+
for (const module of [...usedOperations.keys()].sort()) {
|
|
164
|
+
const contract = resolveModuleVersion(contracts, module, ranges.get(module) ?? universalRange)
|
|
165
|
+
const candidates = providers.providersFor(target, module, contract.version)
|
|
166
|
+
|
|
167
|
+
if (candidates.length == 0) {
|
|
168
|
+
throw new SemantifoldDiagnostic({
|
|
169
|
+
code: "STDLIB_PROVIDER_MISSING",
|
|
170
|
+
language: target,
|
|
171
|
+
message: `No registered provider serves module '${module}' version '${contract.version}'.`
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
if (candidates.length > 1) {
|
|
175
|
+
throw new SemantifoldDiagnostic({
|
|
176
|
+
code: "STDLIB_PROVIDER_AMBIGUOUS",
|
|
177
|
+
language: target,
|
|
178
|
+
message: `Multiple registered providers serve module '${module}' version '${contract.version}'.`
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
const provider = /** @type {StdlibProviderRecord} */ (candidates[0])
|
|
182
|
+
|
|
183
|
+
selectedProviders.set(module, provider)
|
|
184
|
+
for (const dependency of provider.dependencies) {
|
|
185
|
+
if (!contracts.modules.some(({identity}) => identity == dependency.module)) {
|
|
186
|
+
throw new SemantifoldDiagnostic({
|
|
187
|
+
code: "STDLIB_PROVIDER_DEPENDENCY_MISSING",
|
|
188
|
+
language: provider.identity,
|
|
189
|
+
message: `Provider dependency module '${dependency.module}' is not registered.`
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
if (addRange(dependency.module, asVersionRange(dependency.range))) stable = false
|
|
193
|
+
if (!usedOperations.has(dependency.module)) {
|
|
194
|
+
usedOperations.set(dependency.module, new Set())
|
|
195
|
+
stable = false
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (const module of [...usedOperations.keys()].sort()) {
|
|
201
|
+
const provider = /** @type {StdlibProviderRecord} */ (selectedProviders.get(module))
|
|
202
|
+
const provided = new Set(provider.provides[0].operations)
|
|
203
|
+
const missing = [.../** @type {Set<string>} */ (usedOperations.get(module))].sort()
|
|
204
|
+
.filter((operation) => !provided.has(operation))
|
|
205
|
+
|
|
206
|
+
if (missing.length > 0) {
|
|
207
|
+
throw new SemantifoldDiagnostic({
|
|
208
|
+
code: "STDLIB_PROVIDER_MISSING",
|
|
209
|
+
language: target,
|
|
210
|
+
message: `Provider '${provider.identity}' does not provide operation${missing.length > 1 ? "s" : ""} '${missing.join("', '")}' of module '${module}'.`
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
assertAcyclic(contracts, ranges, usedOperations, selectedProviders)
|
|
215
|
+
/** @type {{identity: string, operations: string[], version: string}[]} */
|
|
216
|
+
const modules = [...usedOperations.keys()].sort().map((identity) => {
|
|
217
|
+
const contract = resolveModuleVersion(contracts, identity, ranges.get(identity) ?? universalRange)
|
|
218
|
+
const used = /** @type {Set<string>} */ (usedOperations.get(identity))
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
identity,
|
|
222
|
+
operations: contract.operations.map(({name}) => name).filter((name) => used.has(name)),
|
|
223
|
+
version: contract.version
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
/** @type {{identity: string, target: string, module: string, version: string, operations: string[], nativeEntries: Record<string, string>, runtimeProfile: string}[]} */
|
|
227
|
+
const providerResults = [...selectedProviders.values()].sort((left, right) =>
|
|
228
|
+
left.identity < right.identity ? -1 : left.identity > right.identity ? 1 : 0).map((provider) => {
|
|
229
|
+
const module = provider.provides[0].module
|
|
230
|
+
const contract = resolveModuleVersion(contracts, module, ranges.get(module) ?? universalRange)
|
|
231
|
+
const used = /** @type {Set<string>} */ (usedOperations.get(module))
|
|
232
|
+
const operations = contract.operations.map(({name}) => name).filter((name) => used.has(name))
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
identity: provider.identity,
|
|
236
|
+
module,
|
|
237
|
+
nativeEntries: Object.fromEntries(operations.map((operation) => [
|
|
238
|
+
operation,
|
|
239
|
+
/** @type {string} */ (provider.nativeEntries[operation])
|
|
240
|
+
])),
|
|
241
|
+
operations,
|
|
242
|
+
runtimeProfile: provider.runtimeProfile,
|
|
243
|
+
target: provider.target,
|
|
244
|
+
version: provider.provides[0].version
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
return deepFreeze(/** @type {StdlibNegotiationResult} */ ({modules, providers: providerResults, target}))
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Resolves the highest registered contract version satisfying one combined range.
|
|
252
|
+
* @param {StdlibContractRegistry} contracts - Canonical contract registry.
|
|
253
|
+
* @param {string} module - Canonical module identity.
|
|
254
|
+
* @param {VersionRange} range - Combined half-open range.
|
|
255
|
+
* @returns {import("./semantic/stdlib.js").StdlibContract} Exact-version contract.
|
|
256
|
+
*/
|
|
257
|
+
function resolveModuleVersion(contracts, module, range) {
|
|
258
|
+
const listed = contracts.modules.find(({identity}) => identity == module)
|
|
259
|
+
|
|
260
|
+
if (!listed) {
|
|
261
|
+
throw new SemantifoldDiagnostic({code: "STDLIB_MODULE_UNKNOWN", language: module, message: `Canonical module '${module}' is not registered.`})
|
|
262
|
+
}
|
|
263
|
+
/** @type {[number, number, number] | null} */
|
|
264
|
+
let resolved = null
|
|
265
|
+
|
|
266
|
+
for (const version of listed.versions) {
|
|
267
|
+
const tuple = /** @type {[number, number, number]} */ (parseStdlibVersion(version))
|
|
268
|
+
|
|
269
|
+
if (stdlibVersionSatisfies(tuple, range) && (resolved === null || compareStdlibVersions(tuple, resolved) > 0)) {
|
|
270
|
+
resolved = tuple
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (resolved === null) {
|
|
274
|
+
throw new SemantifoldDiagnostic({
|
|
275
|
+
code: "STDLIB_VERSION_INCOMPATIBLE",
|
|
276
|
+
language: module,
|
|
277
|
+
message: `Canonical module '${module}' has no registered version satisfying the combined range.`
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
return contracts.resolveModule(module, `${resolved[0]}.${resolved[1]}.${resolved[2]}`)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Fails deterministically when canonical operation dependencies or selected provider
|
|
285
|
+
* module dependencies cycle.
|
|
286
|
+
* @param {StdlibContractRegistry} contracts - Canonical contract registry.
|
|
287
|
+
* @param {Map<string, VersionRange>} ranges - Combined ranges per module.
|
|
288
|
+
* @param {Map<string, Set<string>>} usedOperations - Used operations per module.
|
|
289
|
+
* @param {Map<string, StdlibProviderRecord>} selectedProviders - Selected provider per module.
|
|
290
|
+
* @returns {void}
|
|
291
|
+
*/
|
|
292
|
+
function assertAcyclic(contracts, ranges, usedOperations, selectedProviders) {
|
|
293
|
+
/** @type {Map<string, string[]>} */
|
|
294
|
+
const edges = new Map()
|
|
295
|
+
|
|
296
|
+
for (const module of [...usedOperations.keys()].sort()) {
|
|
297
|
+
const contract = resolveModuleVersion(contracts, module, ranges.get(module) ?? universalRange)
|
|
298
|
+
const declared = new Map(contract.operations.map(({dependencies, name}) => [name, dependencies]))
|
|
299
|
+
const used = /** @type {Set<string>} */ (usedOperations.get(module))
|
|
300
|
+
|
|
301
|
+
for (const operation of [...used].sort()) {
|
|
302
|
+
const nodeKey = `${module}\u0000${operation}`
|
|
303
|
+
const targets = /** @type {string[]} */ (edges.get(nodeKey) ?? [])
|
|
304
|
+
|
|
305
|
+
for (const dependency of /** @type {{module: string, operation: string}[]} */ (declared.get(operation))) {
|
|
306
|
+
targets.push(`${dependency.module}\u0000${dependency.operation}`)
|
|
307
|
+
}
|
|
308
|
+
edges.set(nodeKey, targets.sort())
|
|
309
|
+
}
|
|
310
|
+
const moduleNodeKey = `${module}\u0000\u0000`
|
|
311
|
+
const moduleTargets = /** @type {string[]} */ (edges.get(moduleNodeKey) ?? [])
|
|
312
|
+
|
|
313
|
+
for (const dependency of contract.dependencies) moduleTargets.push(`${dependency.module}\u0000\u0000`)
|
|
314
|
+
edges.set(moduleNodeKey, moduleTargets.sort())
|
|
315
|
+
}
|
|
316
|
+
for (const module of [...selectedProviders.keys()].sort()) {
|
|
317
|
+
const provider = /** @type {StdlibProviderRecord} */ (selectedProviders.get(module))
|
|
318
|
+
const nodeKey = `${module}\u0000\u0000`
|
|
319
|
+
const targets = /** @type {string[]} */ (edges.get(nodeKey) ?? [])
|
|
320
|
+
|
|
321
|
+
for (const dependency of provider.dependencies) {
|
|
322
|
+
targets.push(`${dependency.module}\u0000\u0000`)
|
|
323
|
+
}
|
|
324
|
+
edges.set(nodeKey, targets.sort())
|
|
325
|
+
}
|
|
326
|
+
/** @type {Map<string, number>} */
|
|
327
|
+
const colors = new Map()
|
|
328
|
+
/**
|
|
329
|
+
* Walks the dependency edges in deterministic order, rejecting cycles.
|
|
330
|
+
* @param {string} nodeKey - Node key.
|
|
331
|
+
* @returns {void}
|
|
332
|
+
*/
|
|
333
|
+
function visit(nodeKey) {
|
|
334
|
+
colors.set(nodeKey, 1)
|
|
335
|
+
|
|
336
|
+
for (const target of /** @type {string[]} */ (edges.get(nodeKey) ?? [])) {
|
|
337
|
+
const color = colors.get(target) ?? 0
|
|
338
|
+
|
|
339
|
+
if (color == 1) throw new SemantifoldDiagnostic({
|
|
340
|
+
code: "STDLIB_PROVIDER_CYCLE",
|
|
341
|
+
language: target.split("\u0000")[0],
|
|
342
|
+
message: "Canonical stdlib dependencies form a cycle."
|
|
343
|
+
})
|
|
344
|
+
if (color == 0) visit(target)
|
|
345
|
+
}
|
|
346
|
+
colors.set(nodeKey, 2)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
for (const nodeKey of [...edges.keys()].sort()) {
|
|
350
|
+
if ((colors.get(nodeKey) ?? 0) == 0) visit(nodeKey)
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Normalizes a declared dependency range, accepting canonical strings or parsed ranges.
|
|
356
|
+
* @param {unknown} value - Candidate range.
|
|
357
|
+
* @returns {VersionRange} Half-open range.
|
|
358
|
+
*/
|
|
359
|
+
function asVersionRange(value) {
|
|
360
|
+
if (typeof value == "string") {
|
|
361
|
+
const parsed = parseStdlibVersionRange(value)
|
|
362
|
+
|
|
363
|
+
if (parsed === null) malformedRange(value)
|
|
364
|
+
return parsed
|
|
365
|
+
}
|
|
366
|
+
if (isPlainObject(value) && Array.isArray(value.lower) && value.lower.length == 3 &&
|
|
367
|
+
value.lower.every((part) => Number.isInteger(part)) &&
|
|
368
|
+
(value.upper === null || (Array.isArray(value.upper) && value.upper.length == 3 &&
|
|
369
|
+
value.upper.every((part) => Number.isInteger(part))))) {
|
|
370
|
+
return {lower: /** @type {[number, number, number]} */ (value.lower), upper: value.upper === null ? null : /** @type {[number, number, number]} */ (value.upper)}
|
|
371
|
+
}
|
|
372
|
+
return malformedRange(String(value))
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Encodes one half-open range deterministically.
|
|
377
|
+
* @param {VersionRange} range - Half-open range.
|
|
378
|
+
* @returns {string} Stable key.
|
|
379
|
+
*/
|
|
380
|
+
function rangeKey(range) {
|
|
381
|
+
return `${range.lower.join(".")}..${range.upper === null ? "" : range.upper.join(".")}`
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Throws a malformed-version-range diagnostic.
|
|
386
|
+
* @param {string} range - Candidate range.
|
|
387
|
+
* @returns {never} Always throws.
|
|
388
|
+
*/
|
|
389
|
+
function malformedRange(range) {
|
|
390
|
+
throw new SemantifoldDiagnostic({
|
|
391
|
+
code: "STDLIB_VERSION_MALFORMED",
|
|
392
|
+
language: "stdlib",
|
|
393
|
+
message: `Stdlib version range '${range}' is not canonical.`
|
|
394
|
+
})
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Throws an undeclared-operation diagnostic.
|
|
399
|
+
* @param {string} module - Canonical module identity.
|
|
400
|
+
* @param {string} operation - Missing operation.
|
|
401
|
+
* @returns {never} Always throws.
|
|
402
|
+
*/
|
|
403
|
+
function undeclaredOperation(module, operation) {
|
|
404
|
+
throw new SemantifoldDiagnostic({
|
|
405
|
+
code: "STDLIB_OPERATION_UNDECLARED",
|
|
406
|
+
language: module,
|
|
407
|
+
message: `Operation '${operation}' is not declared by canonical module '${module}'.`
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Throws a requirement-shape diagnostic.
|
|
413
|
+
* @param {string} message - Failure detail.
|
|
414
|
+
* @returns {never} Always throws.
|
|
415
|
+
*/
|
|
416
|
+
function invalidRequirement(message) {
|
|
417
|
+
throw new SemantifoldDiagnostic({code: "STDLIB_CONTRACT_INVALID", language: "stdlib", message})
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Checks for an ordinary string-keyed object.
|
|
422
|
+
* @param {unknown} value - Candidate value.
|
|
423
|
+
* @returns {value is Record<string, unknown>} Whether the value is a plain object.
|
|
424
|
+
*/
|
|
425
|
+
function isPlainObject(value) {
|
|
426
|
+
if (typeof value != "object" || value === null) return false
|
|
427
|
+
const prototype = Object.getPrototypeOf(value)
|
|
428
|
+
|
|
429
|
+
return prototype === Object.prototype || prototype === null
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Deep-freezes a detached value.
|
|
434
|
+
* @template T
|
|
435
|
+
* @param {T} value - Detached value.
|
|
436
|
+
* @returns {Readonly<T>} Frozen value.
|
|
437
|
+
*/
|
|
438
|
+
function deepFreeze(value) {
|
|
439
|
+
if (typeof value != "object" || value === null || Object.isFrozen(value)) return /** @type {Readonly<T>} */ (value)
|
|
440
|
+
Object.freeze(value)
|
|
441
|
+
|
|
442
|
+
for (const property of Object.getOwnPropertyNames(value)) {
|
|
443
|
+
deepFreeze(/** @type {unknown} */ ((/** @type {Record<string, unknown>} */ (value))[property]))
|
|
444
|
+
}
|
|
445
|
+
return /** @type {Readonly<T>} */ (value)
|
|
446
|
+
}
|