@pulse-compute/wasm-library-kit 0.0.0 → 1.0.0-beta.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.
@@ -0,0 +1,243 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const {
7
+ PACKAGE_CONTRACT_CATALOG_VERSION,
8
+ PACKAGE_CONTRACT_DISCOVERY_VERSION,
9
+ PACKAGE_PRODUCT_METADATA_PACKAGE_POLICY,
10
+ PACKAGE_NATIVE_LOWERING_TRUST_POLICY,
11
+ normalizePackageContract,
12
+ validatePackageContractCatalog
13
+ } = loadPackageContractAuthority();
14
+ const { discoverLowerableLibraryManifests } = require('./handler-library-contracts.js');
15
+
16
+
17
+ function loadPackageContractAuthority() {
18
+ try {
19
+ return require('@pulse-compute/wasm-contracts/package/package-contract');
20
+ } catch (error) {
21
+ if (error && error.code === 'MODULE_NOT_FOUND' && String(error.message).includes('@pulse-compute/wasm-contracts')) {
22
+ return require('../../../contracts/src/package/package-contract.js');
23
+ }
24
+ throw error;
25
+ }
26
+ }
27
+
28
+ function readJson(file) {
29
+ if (!fs.existsSync(file)) return undefined;
30
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
31
+ }
32
+
33
+ function findWorkspaceRoot(cwd) {
34
+ let current = path.resolve(cwd || process.cwd());
35
+ while (true) {
36
+ const packageJson = readJson(path.join(current, 'package.json'));
37
+ if ((packageJson && packageJson.workspaces) || fs.existsSync(path.join(current, 'pnpm-workspace.yaml'))) return current;
38
+ const parent = path.dirname(current);
39
+ if (parent === current) return path.resolve(cwd || process.cwd());
40
+ current = parent;
41
+ }
42
+ }
43
+
44
+ function workspacePatterns(root) {
45
+ const packageJson = readJson(path.join(root, 'package.json')) || {};
46
+ if (Array.isArray(packageJson.workspaces)) return packageJson.workspaces;
47
+ if (packageJson.workspaces && Array.isArray(packageJson.workspaces.packages)) return packageJson.workspaces.packages;
48
+ const pnpmWorkspace = path.join(root, 'pnpm-workspace.yaml');
49
+ if (!fs.existsSync(pnpmWorkspace)) return ['packages/*'];
50
+ return fs.readFileSync(pnpmWorkspace, 'utf8')
51
+ .split(/\r?\n/)
52
+ .map((line) => line.trim().replace(/^-\s*/, '').replace(/^['"]|['"]$/g, ''))
53
+ .filter((line) => line && !line.startsWith('#'));
54
+ }
55
+
56
+ function expandPattern(root, pattern) {
57
+ const normalized = String(pattern || '').replace(/\\/g, '/');
58
+ if (!normalized.endsWith('/*')) return [];
59
+ const parent = path.resolve(root, normalized.slice(0, -2));
60
+ if (!fs.existsSync(parent)) return [];
61
+ return fs.readdirSync(parent, { withFileTypes: true })
62
+ .filter((entry) => entry.isDirectory())
63
+ .map((entry) => path.join(parent, entry.name));
64
+ }
65
+
66
+ function nodeModulesPackageDirs(root, cwd) {
67
+ const roots = new Set([path.join(root, 'node_modules')]);
68
+ let current = path.resolve(cwd || root);
69
+ while (true) {
70
+ roots.add(path.join(current, 'node_modules'));
71
+ if (current === path.resolve(root)) break;
72
+ const parent = path.dirname(current);
73
+ if (parent === current) break;
74
+ current = parent;
75
+ }
76
+ const dirs = [];
77
+ for (const nodeModulesRoot of roots) {
78
+ if (!fs.existsSync(nodeModulesRoot)) continue;
79
+ for (const entry of fs.readdirSync(nodeModulesRoot, { withFileTypes: true })) {
80
+ if ((!entry.isDirectory() && !entry.isSymbolicLink()) || entry.name.startsWith('.')) continue;
81
+ const full = path.join(nodeModulesRoot, entry.name);
82
+ if (!entry.name.startsWith('@')) {
83
+ dirs.push(full);
84
+ continue;
85
+ }
86
+ if (!fs.existsSync(full)) continue;
87
+ for (const child of fs.readdirSync(full, { withFileTypes: true })) {
88
+ if ((child.isDirectory() || child.isSymbolicLink()) && !child.name.startsWith('.')) dirs.push(path.join(full, child.name));
89
+ }
90
+ }
91
+ }
92
+ return dirs;
93
+ }
94
+
95
+ function packageContractPath(packageJson) {
96
+ const pulse = packageJson && packageJson.pulse;
97
+ return pulse && typeof pulse === 'object' && typeof pulse.contract === 'string' ? pulse.contract : undefined;
98
+ }
99
+
100
+ function resolveInsidePackage(packageDir, reference, field, expectedKind = 'file') {
101
+ const root = path.resolve(packageDir);
102
+ const resolved = path.resolve(packageDir, reference);
103
+ const relative = path.relative(root, resolved);
104
+ if (relative.startsWith('..') || path.isAbsolute(relative)) throw new TypeError(`${field} must remain inside ${root}.`);
105
+ if (!fs.existsSync(resolved)) throw new TypeError(`${field} does not exist: ${reference}.`);
106
+ const stat = fs.statSync(resolved);
107
+ if (expectedKind === 'file' && !stat.isFile()) throw new TypeError(`${field} must identify a file: ${reference}.`);
108
+ if (expectedKind === 'directory' && !stat.isDirectory()) throw new TypeError(`${field} must identify a directory: ${reference}.`);
109
+ return resolved;
110
+ }
111
+
112
+ function loadContract(file) {
113
+ if (path.extname(file) !== '.json') throw new TypeError(`Pulse product metadata must be static JSON: ${file}.`);
114
+ const value = readJson(file);
115
+ if (!value) throw new TypeError(`Pulse product metadata is not valid JSON: ${file}.`);
116
+ return normalizePackageContract(value);
117
+ }
118
+
119
+ function sha256(value) {
120
+ return crypto.createHash('sha256').update(value).digest('hex');
121
+ }
122
+
123
+ function sortedUnique(values) {
124
+ return [...new Set(values || [])].sort();
125
+ }
126
+
127
+ function validateLowererAlignment(contract, lowerable, packageDir) {
128
+ if (contract.targets.native.status !== 'supported') return null;
129
+ if (!lowerable) throw new TypeError(`Native package contract ${contract.contractId} has no package-owned lowering manifest.`);
130
+ const manifest = lowerable.manifest;
131
+ if (manifest.contractId !== contract.contractId) throw new TypeError(`Package contract ${contract.contractId} does not match lowerer contract ${manifest.contractId}.`);
132
+ if (manifest.npmPackage !== contract.npmPackage) throw new TypeError(`Package contract ${contract.contractId} lowerer package does not match ${contract.npmPackage}.`);
133
+ if (manifest.lowerableSubpath !== contract.targets.native.lowerableSubpath) throw new TypeError(`Package contract ${contract.contractId} lowerable subpath does not match the trusted lowerer manifest.`);
134
+ const expectedManifest = path.relative(packageDir, lowerable.manifestFile).replace(/\\/g, '/').replace(/^(?!\.)/, './');
135
+ if (contract.lowering.manifest !== expectedManifest) throw new TypeError(`Package contract ${contract.contractId} lowering.manifest must identify ${expectedManifest}.`);
136
+ const manifestRequirements = sortedUnique(manifest.modes && manifest.modes.wasm && manifest.modes.wasm.hostCapabilities || []);
137
+ if (JSON.stringify(manifestRequirements) !== JSON.stringify([...contract.targets.native.providerRequirements])) {
138
+ throw new TypeError(`Package contract ${contract.contractId} provider requirements do not match the trusted lowerer manifest.`);
139
+ }
140
+ const manifestSymbols = sortedUnique(manifest.facade && manifest.facade.symbols || []);
141
+ if (manifest.lowerableSubpath !== contract.authoring.import || JSON.stringify(manifestSymbols) !== JSON.stringify([...contract.authoring.symbols])) {
142
+ throw new TypeError(`Package contract ${contract.contractId} authoring facade does not match the trusted lowerer manifest.`);
143
+ }
144
+ const semanticCases = sortedUnique(manifest.modes && manifest.modes.wasm && manifest.modes.wasm.lowerings
145
+ ? manifest.modes.wasm.lowerings.map((entry) => entry.tsSymbol)
146
+ : []);
147
+ if (JSON.stringify(semanticCases) !== JSON.stringify([...contract.conformance.semanticCases])) {
148
+ throw new TypeError(`Package contract ${contract.contractId} semantic cases do not match the trusted lowerer operations.`);
149
+ }
150
+ return Object.freeze({ manifest, manifestFile: lowerable.manifestFile, manifestRequirements, semanticCases });
151
+ }
152
+
153
+ function validateOwnedPaths(contract, packageDir) {
154
+ for (const root of contract.conformance.fixtureRoots) resolveInsidePackage(packageDir, root, `${contract.contractId} conformance.fixtureRoots`, 'directory');
155
+ if (contract.docs.readme) resolveInsidePackage(packageDir, contract.docs.readme, `${contract.contractId} docs.readme`);
156
+ if (contract.docs.contract) resolveInsidePackage(packageDir, contract.docs.contract, `${contract.contractId} docs.contract`);
157
+ }
158
+
159
+ function discoverPulsePackageContracts(inputs = {}) {
160
+ const cwd = path.resolve(inputs.cwd || process.cwd());
161
+ const workspaceRoot = path.resolve(inputs.workspaceRoot || findWorkspaceRoot(cwd));
162
+ const workspaceDirs = workspacePatterns(workspaceRoot).flatMap((pattern) => expandPattern(workspaceRoot, pattern)).map((entry) => path.resolve(entry));
163
+ const externalDirs = inputs.scanNodeModules === false ? [] : nodeModulesPackageDirs(workspaceRoot, cwd).map((entry) => path.resolve(entry));
164
+ const packageDirs = [];
165
+ const seenPackageDirs = new Set();
166
+ for (const packageDir of [...workspaceDirs, ...externalDirs]) {
167
+ const resolved = path.resolve(packageDir);
168
+ const identity = fs.existsSync(resolved) ? fs.realpathSync.native(resolved) : resolved;
169
+ if (seenPackageDirs.has(identity)) continue;
170
+ seenPackageDirs.add(identity);
171
+ packageDirs.push(resolved);
172
+ }
173
+ const lowerableByPackage = new Map(discoverLowerableLibraryManifests({
174
+ cwd,
175
+ workspaceRoot,
176
+ scanNodeModules: inputs.scanNodeModules !== false
177
+ }).map((record) => [record.packageName, record]));
178
+ const records = [];
179
+
180
+ for (const packageDir of packageDirs) {
181
+ const packageJsonFile = path.join(packageDir, 'package.json');
182
+ const packageJson = readJson(packageJsonFile);
183
+ const contractRef = packageContractPath(packageJson);
184
+ if (!packageJson || !contractRef) continue;
185
+ if (typeof packageJson.name !== 'string' || packageJson.name.trim().length === 0) {
186
+ throw new TypeError('Pulse package contracts require package.json name.');
187
+ }
188
+ const contractFile = resolveInsidePackage(packageDir, contractRef, `${packageJson.name} package.json pulse.contract`);
189
+ const contract = loadContract(contractFile);
190
+ if (contract.npmPackage !== packageJson.name) throw new TypeError(`Pulse package contract ${contract.contractId} declares ${contract.npmPackage}, but package.json declares ${packageJson.name}.`);
191
+ validateOwnedPaths(contract, packageDir);
192
+ const lowerer = validateLowererAlignment(contract, lowerableByPackage.get(packageJson.name), packageDir);
193
+ records.push(Object.freeze({
194
+ version: PACKAGE_CONTRACT_DISCOVERY_VERSION,
195
+ packageDir,
196
+ packageJsonFile,
197
+ packageName: packageJson.name,
198
+ packageVersion: String(packageJson.version || '0.0.0'),
199
+ contractFile,
200
+ contract,
201
+ contractHash: sha256(JSON.stringify(contract)),
202
+ source: workspaceDirs.includes(packageDir) ? 'workspace' : 'node_modules',
203
+ lowerableManifestFile: lowerer && lowerer.manifestFile || null
204
+ }));
205
+ }
206
+
207
+ const catalog = validatePackageContractCatalog(records.map((entry) => entry.contract));
208
+ const byContract = new Map(records.map((entry) => [entry.contract.contractId, entry]));
209
+ const contracts = catalog.contracts.map((contract) => {
210
+ const record = byContract.get(contract.contractId);
211
+ return Object.freeze({
212
+ ...contract,
213
+ metadataHash: record.contractHash,
214
+ packageVersion: record.packageVersion,
215
+ source: record.source
216
+ });
217
+ });
218
+ return Object.freeze({
219
+ version: catalog.version,
220
+ discoveryVersion: PACKAGE_CONTRACT_DISCOVERY_VERSION,
221
+ contracts: Object.freeze(contracts),
222
+ profileFragments: catalog.profileFragments,
223
+ helperImports: catalog.helperImports,
224
+ records: Object.freeze(records),
225
+ policy: Object.freeze({
226
+ ...catalog.policy,
227
+ productMetadataPackages: PACKAGE_PRODUCT_METADATA_PACKAGE_POLICY,
228
+ nativeLoweringTrust: PACKAGE_NATIVE_LOWERING_TRUST_POLICY,
229
+ absolutePathsExcludedFromCatalog: true,
230
+ applicationCodeHooks: false,
231
+ dynamicRegistration: false
232
+ })
233
+ });
234
+ }
235
+
236
+ module.exports = Object.freeze({
237
+ PACKAGE_CONTRACT_DISCOVERY_VERSION,
238
+ PACKAGE_PRODUCT_METADATA_PACKAGE_POLICY,
239
+ PACKAGE_NATIVE_LOWERING_TRUST_POLICY,
240
+ discoverPulsePackageContracts,
241
+ packageContractPath,
242
+ loadContract
243
+ });
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ discoverLowerableLibraryManifests,
5
+ loadLowerableCompilerBuilder,
6
+ resolveDefaultLibraryContracts,
7
+ invokeLowerableCompilerBuilder
8
+ } = require('./handler-library-contracts.js');
9
+
10
+ function findLowerableManifestRecord(inputs = {}) {
11
+ const cwd = inputs.cwd || process.cwd();
12
+ const manifestRecords = Array.isArray(inputs.manifestRecords) && inputs.manifestRecords.length > 0
13
+ ? inputs.manifestRecords
14
+ : discoverLowerableLibraryManifests({ cwd, workspaceRoot: inputs.workspaceRoot, scanNodeModules: inputs.scanNodeModules });
15
+ const contractId = inputs.contractId;
16
+ const npmPackage = inputs.npmPackage;
17
+ const lowerableSubpath = inputs.lowerableSubpath;
18
+ const record = manifestRecords.find((entry) => {
19
+ const manifest = entry.manifest || {};
20
+ if (contractId && manifest.contractId !== contractId) return false;
21
+ if (npmPackage && manifest.npmPackage !== npmPackage) return false;
22
+ if (lowerableSubpath && manifest.lowerableSubpath !== lowerableSubpath) return false;
23
+ return true;
24
+ });
25
+ return { record, manifestRecords };
26
+ }
27
+
28
+ function buildPackageOwnedLoweringPlan(inputs = {}) {
29
+ const cwd = inputs.cwd || process.cwd();
30
+ const { record, manifestRecords } = findLowerableManifestRecord(inputs);
31
+ if (!record) {
32
+ const selector = inputs.contractId || inputs.npmPackage || inputs.lowerableSubpath || '<unspecified lowerable package>';
33
+ const error = new Error(`Could not discover package-owned lowerable manifest for ${selector}.`);
34
+ error.diagnostics = [];
35
+ throw error;
36
+ }
37
+ const loaded = loadLowerableCompilerBuilder(record);
38
+ const libraryContracts = Array.isArray(inputs.libraryContracts) && inputs.libraryContracts.length > 0
39
+ ? inputs.libraryContracts
40
+ : resolveDefaultLibraryContracts({ cwd, workspaceRoot: inputs.workspaceRoot });
41
+ return invokeLowerableCompilerBuilder(loaded, record, libraryContracts, inputs);
42
+ }
43
+
44
+ module.exports = {
45
+ findLowerableManifestRecord,
46
+ buildPackageOwnedLoweringPlan
47
+ };
package/src/index.js ADDED
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ const compiler = require('./compiler');
4
+
5
+ module.exports = {
6
+ compiler,
7
+ ...compiler
8
+ };