@platforma-sdk/tengo-builder 2.5.30 → 3.0.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.
Files changed (37) hide show
  1. package/dist/compiler/compiler.cjs +48 -1
  2. package/dist/compiler/compiler.cjs.map +1 -1
  3. package/dist/compiler/compiler.js +47 -1
  4. package/dist/compiler/compiler.js.map +1 -1
  5. package/dist/compiler/main.cjs +132 -6
  6. package/dist/compiler/main.cjs.map +1 -1
  7. package/dist/compiler/main.js +132 -6
  8. package/dist/compiler/main.js.map +1 -1
  9. package/dist/compiler/pack_limits.cjs +49 -0
  10. package/dist/compiler/pack_limits.cjs.map +1 -0
  11. package/dist/compiler/pack_limits.js +47 -0
  12. package/dist/compiler/pack_limits.js.map +1 -0
  13. package/dist/compiler/package.cjs.map +1 -1
  14. package/dist/compiler/package.js.map +1 -1
  15. package/dist/compiler/source.cjs +6 -2
  16. package/dist/compiler/source.cjs.map +1 -1
  17. package/dist/compiler/source.js +6 -2
  18. package/dist/compiler/source.js.map +1 -1
  19. package/dist/shared/basecmd.cjs +2 -1
  20. package/dist/shared/basecmd.cjs.map +1 -1
  21. package/dist/shared/basecmd.js +2 -1
  22. package/dist/shared/basecmd.js.map +1 -1
  23. package/dist/shared/dump.cjs +4 -0
  24. package/dist/shared/dump.cjs.map +1 -1
  25. package/dist/shared/dump.js +4 -0
  26. package/dist/shared/dump.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/compiler/compiler.test.ts +91 -0
  29. package/src/compiler/compiler.ts +72 -1
  30. package/src/compiler/main.ts +217 -11
  31. package/src/compiler/pack_limits.test.ts +173 -0
  32. package/src/compiler/pack_limits.ts +103 -0
  33. package/src/compiler/package.ts +1 -1
  34. package/src/compiler/source.test.ts +30 -0
  35. package/src/compiler/source.ts +4 -0
  36. package/src/shared/basecmd.ts +1 -1
  37. package/src/shared/dump.ts +9 -0
@@ -4,6 +4,7 @@ const require_package = require("./package.cjs");
4
4
  const require_template = require("./template.cjs");
5
5
  const require_compiler = require("./compiler.cjs");
6
6
  const require_source = require("./source.cjs");
7
+ const require_pack_limits = require("./pack_limits.cjs");
7
8
  let node_path = require("node:path");
8
9
  node_path = require_runtime.__toESM(node_path);
9
10
  let node_fs = require("node:fs");
@@ -11,10 +12,13 @@ node_fs = require_runtime.__toESM(node_fs);
11
12
  let _milaboratories_pl_model_backend = require("@milaboratories/pl-model-backend");
12
13
  let _milaboratories_resolve_helper = require("@milaboratories/resolve-helper");
13
14
  //#region src/compiler/main.ts
15
+ const wasmExportCondition = "wasm";
16
+ const defaultWasmExportId = "main";
14
17
  const compiledTplSuffix = ".plj.gz";
15
18
  const compiledLibSuffix = ".lib.tengo";
16
19
  const compiledSoftwareSuffix = ".sw.json";
17
20
  const compiledAssetSuffix = ".as.json";
21
+ const compiledWasmSuffix = ".wasm";
18
22
  const srcTestSuffix = ".test.tengo";
19
23
  const srcTplSuffix = ".tpl.tengo";
20
24
  const srcLibSuffix = ".lib.tengo";
@@ -42,11 +46,20 @@ function resolvePackageJsonPackage(root, depPackageName) {
42
46
  } while (depth < 7 && node_path.basename(resolved) !== "node_modules");
43
47
  }
44
48
  const resolved2 = (0, _milaboratories_resolve_helper.tryResolveOrError)(root, `${depPackageName}/package.json`);
45
- if (resolved2.result === void 0) {
46
- if (resolved2.err === "ERR_PACKAGE_PATH_NOT_EXPORTED") return void 0;
47
- throw new Error(`Can't resolve package.json for package ${depPackageName ?? "."} relative to ${root}`);
49
+ if (resolved2.result !== void 0) return resolved2.result;
50
+ if (resolved2.err === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
51
+ const fromNodeModules = findInNodeModules(root, depPackageName);
52
+ if (fromNodeModules !== void 0) return fromNodeModules;
53
+ return;
48
54
  }
49
- return resolved2.result;
55
+ throw new Error(`Can't resolve package.json for package ${depPackageName ?? "."} relative to ${root}`);
56
+ }
57
+ function findInNodeModules(root, depPackageName) {
58
+ const candidate = node_path.join(root, "node_modules", depPackageName, "package.json");
59
+ if (require_util.pathType(candidate) === "file") return candidate;
60
+ const parent = node_path.dirname(root);
61
+ if (parent === root) return void 0;
62
+ return findInNodeModules(parent, depPackageName);
50
63
  }
51
64
  function resolvePackageJsonRoot(root) {
52
65
  if (!node_path.isAbsolute(root)) throw new Error(`Root path must be absolute: ${root}`);
@@ -97,6 +110,9 @@ function resolveSoftwareDst(mode, root) {
97
110
  function resolveAssetsDst(mode, root) {
98
111
  return node_path.resolve(root, mode, "tengo", "asset");
99
112
  }
113
+ function resolveWasmDst(mode, root) {
114
+ return node_path.resolve(root, mode, "tengo", "wasm");
115
+ }
100
116
  function loadDependencies(logger, compiler, packageInfo) {
101
117
  for (const dep of packageInfo.dependencies) loadDependencies(logger, compiler, dep);
102
118
  if (packageInfo.context === "root") return;
@@ -104,11 +120,14 @@ function loadDependencies(logger, compiler, packageInfo) {
104
120
  const tplDistFolder = resolveTemplatesDst("dist", packageInfo.root);
105
121
  const softwareDistFolder = resolveSoftwareDst("dist", packageInfo.root);
106
122
  const assetDistFolder = resolveAssetsDst("dist", packageInfo.root);
123
+ const wasmDistFolder = resolveWasmDst("dist", packageInfo.root);
107
124
  const libDistExists = require_util.pathType(libDistFolder) === "dir";
108
125
  const tplDistExists = require_util.pathType(tplDistFolder) === "dir";
109
126
  const softwareDistExists = require_util.pathType(softwareDistFolder) === "dir";
110
127
  const assetDistExists = require_util.pathType(assetDistFolder) === "dir";
111
- if (!libDistExists && !tplDistExists && !softwareDistExists && !assetDistExists) return;
128
+ const wasmDistExists = require_util.pathType(wasmDistFolder) === "dir";
129
+ const wasmExports = collectWasmExportPaths(packageInfo.root);
130
+ if (!libDistExists && !tplDistExists && !softwareDistExists && !assetDistExists && !wasmDistExists && wasmExports.length === 0) return;
112
131
  const packageId = {
113
132
  name: packageInfo.name,
114
133
  version: packageInfo.version
@@ -117,6 +136,8 @@ function loadDependencies(logger, compiler, packageInfo) {
117
136
  if (tplDistExists) loadTemplatesFromDir(logger, packageId, "dist", tplDistFolder, compiler);
118
137
  if (softwareDistExists) loadSoftwareFromDir(logger, packageId, "dist", softwareDistFolder, compiler);
119
138
  if (assetDistExists) loadAssetsFromDir(logger, packageId, "dist", assetDistFolder, compiler);
139
+ if (wasmDistExists) loadWasmFromDir(logger, packageId, "dist", wasmDistFolder, compiler);
140
+ for (const wasmExport of wasmExports) loadWasmFromExport(logger, packageId, "dist", packageInfo.root, wasmExport, compiler);
120
141
  }
121
142
  function loadLibsFromDir(logger, packageId, mode, folder, compiler) {
122
143
  for (const f of node_fs.readdirSync(folder)) {
@@ -184,6 +205,100 @@ function loadAssetsFromDir(logger, packageId, mode, folder, compiler) {
184
205
  compiler.addAsset(asset);
185
206
  }
186
207
  }
208
+ function loadWasmFromDir(logger, packageId, mode, folder, compiler) {
209
+ for (const f of node_fs.readdirSync(folder)) {
210
+ const file = node_path.resolve(folder, f);
211
+ if (!f.endsWith(compiledWasmSuffix)) throw new Error(`unexpected file in 'wasm' folder: ${file}`);
212
+ addWasmFile(logger, mode, file, {
213
+ type: "wasm",
214
+ pkg: packageId.name,
215
+ id: f.slice(0, f.length - 5),
216
+ version: packageId.version
217
+ }, compiler);
218
+ }
219
+ }
220
+ function loadWasmFromExport(logger, packageId, mode, packageRoot, wasmExport, compiler) {
221
+ const file = node_path.resolve(packageRoot, wasmExport.relPath);
222
+ if (require_util.pathType(file) !== "file") throw new Error(`wasm export "${wasmExport.id}" points to missing file: ${file} (package ${packageId.name})`);
223
+ addWasmFile(logger, mode, file, {
224
+ type: "wasm",
225
+ pkg: packageId.name,
226
+ id: wasmExport.id,
227
+ version: packageId.version
228
+ }, compiler);
229
+ }
230
+ function addWasmFile(logger, mode, file, fullName, compiler) {
231
+ const bytes = node_fs.readFileSync(file);
232
+ require_pack_limits.assertWasmFileSize(file, bytes.length, fullName);
233
+ const source = bytes.toString("base64");
234
+ const wasm = new require_source.ArtifactSource(mode, fullName, require_source.getSha256(source), source, file, [], []);
235
+ logger.debug(`Adding dependency ${require_package.fullNameToString(fullName)} from ${file}`);
236
+ compiler.addWasm(wasm);
237
+ }
238
+ /**
239
+ * Discover wasm artifacts declared by a package's `package.json` via the
240
+ * node `exports` conditional-exports map.
241
+ *
242
+ * Convention: a package that wants to ship one or more wasm components to
243
+ * tengo-builder publishes them under a `"wasm"` condition keyed by an
244
+ * `exports` subpath. The subpath becomes the wasm artifact id (`.` →
245
+ * `main`, `./foo` → `foo`). Example shape we look for:
246
+ *
247
+ * {
248
+ * "exports": {
249
+ * ".": {
250
+ * "wasm": "./dist/pframes_rs_wasip2.wasm", // ← discovered
251
+ * "wit": "./wit/world.wit"
252
+ * },
253
+ * "./extra": {
254
+ * "wasm": "./dist/extra.wasm" // ← discovered as id "extra"
255
+ * }
256
+ * }
257
+ * }
258
+ *
259
+ * Why raw traversal instead of Zod / a typed schema:
260
+ * 1. `package.json#exports` is a community convention with no fixed shape
261
+ * — any combination of strings, objects, arrays, and conditions is
262
+ * legal node syntax. A strict schema would either reject valid
263
+ * packages or have to admit `unknown` for half of it anyway.
264
+ * 2. We care about exactly one condition (`wasm`) on subpath entries,
265
+ * not the rest of the exports tree. A targeted walk reads more
266
+ * directly than a schema that re-describes the conditional-exports
267
+ * grammar.
268
+ * 3. Errors here should always mean "this package contributes no wasm";
269
+ * never crash the build. Every check returns `[]` or `continue`s.
270
+ *
271
+ * Returns the discovered wasm exports; empty when the file is missing,
272
+ * malformed, has no `exports`, or has no subpath with a `"wasm"`
273
+ * condition pointing at a string path.
274
+ */
275
+ function collectWasmExportPaths(packageRoot) {
276
+ const packageJsonPath = node_path.join(packageRoot, "package.json");
277
+ if (require_util.pathType(packageJsonPath) !== "file") return [];
278
+ let raw;
279
+ try {
280
+ raw = JSON.parse(node_fs.readFileSync(packageJsonPath, "utf-8"));
281
+ } catch {
282
+ return [];
283
+ }
284
+ if (typeof raw !== "object" || raw === null) return [];
285
+ const exportsField = raw.exports;
286
+ if (typeof exportsField !== "object" || exportsField === null) return [];
287
+ const result = [];
288
+ for (const [subpath, value] of Object.entries(exportsField)) {
289
+ if (!subpath.startsWith(".")) continue;
290
+ if (typeof value !== "object" || value === null) continue;
291
+ const wasmPath = value[wasmExportCondition];
292
+ if (typeof wasmPath !== "string") continue;
293
+ const id = subpath === "." ? defaultWasmExportId : subpath.replace(/^\.\/?/, "");
294
+ if (!id) continue;
295
+ result.push({
296
+ id,
297
+ relPath: wasmPath
298
+ });
299
+ }
300
+ return result;
301
+ }
187
302
  function parseSources(logger, packageId, mode, root, subdir) {
188
303
  const sources = [];
189
304
  for (const f of node_fs.readdirSync(node_path.join(root, subdir))) {
@@ -276,8 +391,10 @@ function savePacks(logger, compiled, mode) {
276
391
  node_fs.mkdirSync(tplOutput, { recursive: true });
277
392
  for (const tpl of compiled.templates) {
278
393
  const file = node_path.resolve(tplOutput, tpl.fullName.id + compiledTplSuffix);
394
+ const packed = (0, _milaboratories_pl_model_backend.serializeTemplate)(tpl.data);
395
+ require_pack_limits.assertTemplatePackSize(require_package.fullNameToString(tpl.fullName), packed.byteLength, require_pack_limits.collectWasmContributions(tpl.data));
279
396
  logger.info(` - writing ${file}`);
280
- node_fs.writeFileSync(file, (0, _milaboratories_pl_model_backend.serializeTemplate)(tpl.data));
397
+ node_fs.writeFileSync(file, packed);
281
398
  }
282
399
  }
283
400
  if (compiled.software.length > 0) {
@@ -298,6 +415,15 @@ function savePacks(logger, compiled, mode) {
298
415
  node_fs.writeFileSync(file, sw.src);
299
416
  }
300
417
  }
418
+ if (compiled.wasm.length > 0) {
419
+ const wasmOutput = resolveWasmDst(mode, ".");
420
+ node_fs.mkdirSync(wasmOutput, { recursive: true });
421
+ for (const wasm of compiled.wasm) {
422
+ const file = node_path.resolve(wasmOutput, wasm.fullName.id + compiledWasmSuffix);
423
+ logger.info(` - writing ${file}`);
424
+ node_fs.writeFileSync(file, Buffer.from(wasm.src, "base64"));
425
+ }
426
+ }
301
427
  }
302
428
  //#endregion
303
429
  exports.compile = compile;
@@ -1 +1 @@
1
- {"version":3,"file":"main.cjs","names":["path","pathType","fs","parseSourceFile","fullNameToString","typedArtifactNameToString","newTemplateFromContent","templateToSource","ArtifactSource","getSha256","TengoTemplateCompiler"],"sources":["../../src/compiler/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport { pathType } from \"./util\";\nimport type { TemplatesAndLibs } from \"./compiler\";\nimport { TengoTemplateCompiler } from \"./compiler\";\nimport { getSha256 } from \"./source\";\nimport type { CompileMode, FullArtifactName } from \"./package\";\nimport { fullNameToString, typedArtifactNameToString } from \"./package\";\nimport { ArtifactSource, parseSourceFile } from \"./source\";\nimport { newTemplateFromContent, templateToSource } from \"./template\";\nimport type winston from \"winston\";\nimport { tryResolve, tryResolveOrError } from \"@milaboratories/resolve-helper\";\nimport { serializeTemplate } from \"@milaboratories/pl-model-backend\";\n\ninterface PackageId {\n /** Package name from package.json */\n readonly name: string;\n /** Package version from package.json */\n readonly version: string;\n}\n\ninterface PackageInfo extends PackageId {\n /** Package type from package.json */\n readonly type: string | undefined;\n /** Path to package root */\n readonly root: string;\n /** Context of package info */\n readonly context: PackageInfoContext;\n /** Dependencies */\n readonly dependencies: PackageInfo[];\n}\n\ninterface PackageJson {\n name: string;\n version: string;\n type: string | undefined;\n dependencies: Record<string, string>;\n devDependencies: Record<string, string>;\n}\n\nconst compiledTplSuffix = \".plj.gz\";\nconst compiledLibSuffix = \".lib.tengo\";\nconst compiledSoftwareSuffix = \".sw.json\";\nconst compiledAssetSuffix = \".as.json\";\n\n// We need to keep track of dependencies for correct tgo-test CLI utility configuraiton.\n// It is much simpler to do this here, than duplicate all tle logic regarding dependencies\n// in go code.\nconst srcTestSuffix = \".test.tengo\";\n\nconst srcTplSuffix = \".tpl.tengo\";\nconst srcLibSuffix = \".lib.tengo\";\nconst srcSoftwareSuffix = \".sw.json\";\nconst srcAssetSuffix = \".as.json\";\nconst compilableSuffixes = [srcLibSuffix, srcTplSuffix, srcSoftwareSuffix, srcAssetSuffix];\n\n/**\n * Resolves path to package.json file of the given dependency package.\n */\nfunction resolvePackageJsonPackage(root: string, depPackageName: string): string | undefined {\n if (!path.isAbsolute(root)) {\n throw new Error(`Root path must be absolute: ${root}`);\n }\n\n // First approach: resolving package's main entry point and try to find package.json\n // in dir tree upwards.\n let resolved = tryResolve(root, depPackageName);\n if (resolved) {\n let depth = 0;\n do {\n const p = path.join(resolved, \"package.json\");\n if (pathType(p) === \"file\") return p;\n depth++;\n resolved = path.dirname(resolved);\n } while (depth < 7 && path.basename(resolved) !== \"node_modules\");\n }\n\n // Second approach: trying to find package.json in the package dir.\n const resolved2 = tryResolveOrError(root, `${depPackageName}/package.json`);\n if (resolved2.result === undefined) {\n if (resolved2.err === \"ERR_PACKAGE_PATH_NOT_EXPORTED\")\n // tolerating not-exported package.json for dev dependencies\n return undefined;\n throw new Error(\n `Can't resolve package.json for package ${depPackageName ?? \".\"} relative to ${root}`,\n );\n }\n return resolved2.result;\n}\n\nexport function resolvePackageJsonRoot(root: string): string {\n if (!path.isAbsolute(root)) {\n throw new Error(`Root path must be absolute: ${root}`);\n }\n\n const p = path.join(root, \"package.json\");\n if (pathType(p) === \"file\") return p;\n throw new Error(`Can't resolve package.json in ${root}`);\n}\n\ntype PackageInfoContext = \"root\" | \"dependency\" | \"devDependency\";\n\n/**\n * Get package info from package.json and all dependencies.\n */\nexport function getPackageInfo(\n root: string,\n logger: winston.Logger,\n context: PackageInfoContext = \"root\",\n): PackageInfo {\n const packageJsonPath = resolvePackageJsonRoot(root);\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()) as PackageJson;\n\n // resolving dependencies\n const depInfos: PackageInfo[] = [];\n\n if (packageJson.dependencies && context !== \"devDependency\") {\n for (const dep of Object.keys(packageJson.dependencies)) {\n const depPackageJson = resolvePackageJsonPackage(root, dep);\n if (depPackageJson === undefined)\n throw new Error(`Can't resolve package.json for dependency ${dep} of ${root}`);\n const depRoot = path.dirname(depPackageJson);\n depInfos.push(getPackageInfo(depRoot, logger, \"dependency\"));\n }\n }\n\n if (packageJson.devDependencies && context === \"root\") {\n for (const dep of Object.keys(packageJson.devDependencies)) {\n const depPackageJson = resolvePackageJsonPackage(root, dep);\n if (depPackageJson === undefined) {\n logger.warn(`Can't resolve package.json for dev dependency ${dep} of ${root}`);\n // tolerating not-exported package.json for dev dependencies\n continue;\n }\n const depRoot = path.dirname(depPackageJson);\n depInfos.push(getPackageInfo(depRoot, logger, \"devDependency\"));\n }\n }\n\n return {\n name: packageJson.name,\n version: packageJson.version,\n type: packageJson.type,\n dependencies: depInfos,\n root,\n context,\n };\n}\n\nfunction resolveLibsDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"lib\");\n}\n\nfunction resolveTemplatesDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"tpl\");\n}\n\nfunction resolveSoftwareDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"software\");\n}\n\nfunction resolveAssetsDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"asset\");\n}\n\nfunction loadDependencies(\n logger: winston.Logger,\n compiler: TengoTemplateCompiler,\n packageInfo: PackageInfo,\n): void {\n for (const dep of packageInfo.dependencies) loadDependencies(logger, compiler, dep);\n\n if (packageInfo.context === \"root\")\n // we are not reading compiled files for root package\n return;\n\n // we are in package folder\n const libDistFolder = resolveLibsDst(\"dist\", packageInfo.root);\n const tplDistFolder = resolveTemplatesDst(\"dist\", packageInfo.root);\n const softwareDistFolder = resolveSoftwareDst(\"dist\", packageInfo.root);\n const assetDistFolder = resolveAssetsDst(\"dist\", packageInfo.root);\n\n const libDistExists = pathType(libDistFolder) === \"dir\";\n const tplDistExists = pathType(tplDistFolder) === \"dir\";\n const softwareDistExists = pathType(softwareDistFolder) === \"dir\";\n const assetDistExists = pathType(assetDistFolder) === \"dir\";\n\n if (!libDistExists && !tplDistExists && !softwareDistExists && !assetDistExists)\n // if neither of tengo-specific folders detected, skipping package\n return;\n\n const packageId = { name: packageInfo.name, version: packageInfo.version };\n\n if (libDistExists) {\n loadLibsFromDir(logger, packageId, \"dist\", libDistFolder, compiler);\n }\n\n if (tplDistExists) {\n loadTemplatesFromDir(logger, packageId, \"dist\", tplDistFolder, compiler);\n }\n\n if (softwareDistExists) {\n loadSoftwareFromDir(logger, packageId, \"dist\", softwareDistFolder, compiler);\n }\n\n if (assetDistExists) {\n loadAssetsFromDir(logger, packageId, \"dist\", assetDistFolder, compiler);\n }\n}\n\nfunction loadLibsFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledLibSuffix)) throw new Error(`unexpected file in 'lib' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"library\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledLibSuffix.length),\n version: packageId.version,\n };\n const src = parseSourceFile(logger, mode, file, fullName, true);\n compiler.addLib(src);\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n if (src.dependencies.length > 0) {\n logger.debug(\"Dependencies:\");\n for (const dep of src.dependencies) logger.debug(` - ${typedArtifactNameToString(dep)}`);\n }\n }\n}\n\nfunction loadTemplatesFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n // adding templates\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledTplSuffix)) throw new Error(`unexpected file in 'tpl' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"template\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledTplSuffix.length),\n version: packageId.version,\n };\n const tpl = newTemplateFromContent(mode, fullName, fs.readFileSync(file));\n compiler.addTemplate(templateToSource(tpl));\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n }\n}\n\nfunction loadSoftwareFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledSoftwareSuffix))\n throw new Error(`unexpected file in 'software' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"software\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledSoftwareSuffix.length),\n version: packageId.version,\n };\n\n const source = fs.readFileSync(file).toString();\n\n const software = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n compiler.addSoftware(software);\n }\n}\n\nfunction loadAssetsFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledAssetSuffix))\n throw new Error(`unexpected file in 'asset' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"asset\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledAssetSuffix.length),\n version: packageId.version,\n };\n\n const source = fs.readFileSync(file).toString();\n\n const asset = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n compiler.addAsset(asset);\n }\n}\n\nexport function parseSources(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n root: string,\n subdir: string,\n): ArtifactSource[] {\n const sources: ArtifactSource[] = [];\n\n for (const f of fs.readdirSync(path.join(root, subdir))) {\n const inRootPath = path.join(subdir, f); // path to item inside given <root>\n const fullPath = path.join(root, inRootPath); // full path to item from CWD (or abs path, if <root> is abs path)\n\n if (pathType(fullPath) === \"dir\") {\n const nested = parseSources(logger, packageId, mode, root, inRootPath);\n sources.push(...nested);\n continue;\n }\n\n // Handling index.lib.tengo files: rename them to <package-name>.lib.tengo\n const artifactName =\n f === \"index.lib.tengo\" ? `${path.dirname(inRootPath)}.lib.tengo` : inRootPath;\n\n const fullName = fullNameFromFileName(packageId, artifactName.replaceAll(path.sep, \".\"));\n if (!fullName) {\n logger.info(`Skipping unknown file type: ${artifactName}`);\n continue; // skip unknown file types\n }\n\n // if (subdir != '') {\n // throw new Error(`Templates and libraries should reside only inside '${root}' dir.\n // You are free to have any file and dirs structure inside '${root}' keeping other files where you want,\n // but regarding ${compilableSuffixes.join(', ')}, the flat file structure is mandatory.`);\n // }\n\n const file = path.resolve(root, inRootPath);\n logger.debug(`Parsing ${fullNameToString(fullName)} from ${file}`);\n const newSrc = parseSourceFile(logger, mode, file, fullName, true);\n if (newSrc.dependencies.length > 0) {\n logger.debug(\"Detected dependencies:\");\n for (const dep of newSrc.dependencies) logger.debug(` - ${typedArtifactNameToString(dep)}`);\n }\n\n sources.push(newSrc);\n }\n\n return sources;\n}\n\nexport function newCompiler(\n logger: winston.Logger,\n packageInfo: PackageInfo,\n mode: CompileMode,\n): TengoTemplateCompiler {\n const compiler = new TengoTemplateCompiler(mode);\n\n // collect all data (templates, libs and software) from dependency tree\n loadDependencies(logger, compiler, packageInfo);\n\n return compiler;\n}\n\nexport function fullNameFromFileName(\n packageId: PackageId,\n artifactName: string,\n): FullArtifactName | null {\n const pkgAndVersion = { pkg: packageId.name, version: packageId.version };\n if (artifactName.endsWith(srcLibSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcLibSuffix.length),\n type: \"library\",\n };\n }\n\n if (artifactName.endsWith(srcTplSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcTplSuffix.length),\n type: \"template\",\n };\n }\n\n if (artifactName.endsWith(srcSoftwareSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcSoftwareSuffix.length),\n type: \"software\",\n };\n }\n\n if (artifactName.endsWith(srcAssetSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcAssetSuffix.length),\n type: \"asset\",\n };\n }\n\n if (artifactName.endsWith(srcTestSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcTestSuffix.length),\n type: \"test\",\n };\n }\n\n return null;\n}\n\nexport function compile(\n logger: winston.Logger,\n packageInfo: PackageInfo,\n mode: CompileMode,\n): TemplatesAndLibs {\n const compiler = newCompiler(logger, packageInfo, mode);\n const sources = parseSources(logger, packageInfo, mode, \"src\", \"\");\n\n // checking that we have something to do\n if (sources.length === 0) {\n const lookFor: string[] = [];\n for (const suffix of compilableSuffixes) {\n lookFor.push(`*${suffix}`);\n }\n\n logger.error(`Nothing to compile. Looked for ${lookFor.join(\", \")}`);\n process.exit(1);\n }\n\n // compilation\n logger.info(`Compiling '${mode}'...`);\n const compiled = compiler.compileAndAdd(sources);\n logger.debug(`Done.`);\n\n return compiled;\n}\n\nexport function savePacks(logger: winston.Logger, compiled: TemplatesAndLibs, mode: CompileMode) {\n // writing libs\n if (compiled.libs.length > 0) {\n const libOutput = resolveLibsDst(mode, \".\");\n fs.mkdirSync(libOutput, { recursive: true });\n for (const lib of compiled.libs) {\n const file = path.resolve(libOutput, lib.fullName.id + compiledLibSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, lib.src);\n }\n }\n\n // writing templates\n if (compiled.templates.length > 0) {\n const tplOutput = resolveTemplatesDst(mode, \".\");\n fs.mkdirSync(tplOutput, { recursive: true });\n for (const tpl of compiled.templates) {\n const file = path.resolve(tplOutput, tpl.fullName.id + compiledTplSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, serializeTemplate(tpl.data));\n }\n }\n\n // writing software\n if (compiled.software.length > 0) {\n const swOutput = resolveSoftwareDst(mode, \".\");\n fs.mkdirSync(swOutput, { recursive: true });\n for (const sw of compiled.software) {\n const file = path.resolve(swOutput, sw.fullName.id + compiledSoftwareSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, sw.src);\n }\n }\n\n // writing assets\n if (compiled.assets.length > 0) {\n const swOutput = resolveAssetsDst(mode, \".\");\n fs.mkdirSync(swOutput, { recursive: true });\n for (const sw of compiled.software) {\n const file = path.resolve(swOutput, sw.fullName.id + compiledAssetSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, sw.src);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"main.cjs","names":["path","pathType","fs","parseSourceFile","fullNameToString","typedArtifactNameToString","newTemplateFromContent","templateToSource","ArtifactSource","getSha256","TengoTemplateCompiler","collectWasmContributions"],"sources":["../../src/compiler/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport { pathType } from \"./util\";\nimport type { TemplatesAndLibs } from \"./compiler\";\nimport { TengoTemplateCompiler } from \"./compiler\";\nimport { getSha256 } from \"./source\";\nimport type { CompileMode, FullArtifactName } from \"./package\";\nimport { fullNameToString, typedArtifactNameToString } from \"./package\";\nimport { ArtifactSource, parseSourceFile } from \"./source\";\nimport { newTemplateFromContent, templateToSource } from \"./template\";\nimport type winston from \"winston\";\nimport { tryResolve, tryResolveOrError } from \"@milaboratories/resolve-helper\";\nimport { serializeTemplate } from \"@milaboratories/pl-model-backend\";\nimport {\n assertTemplatePackSize,\n assertWasmFileSize,\n collectWasmContributions,\n} from \"./pack_limits\";\n\n// Convention: wasm component packages declare their wasm under a \"wasm\" condition\n// in package.json `exports`. Subpath \".\" maps to the tengo id \"main\"; subpath\n// \"./foo\" maps to id \"foo\". Other shapes of `exports` (string-valued, condition-only)\n// don't produce wasm artifacts.\nconst wasmExportCondition = \"wasm\";\nconst defaultWasmExportId = \"main\";\n\ninterface PackageId {\n /** Package name from package.json */\n readonly name: string;\n /** Package version from package.json */\n readonly version: string;\n}\n\ninterface PackageInfo extends PackageId {\n /** Package type from package.json */\n readonly type: string | undefined;\n /** Path to package root */\n readonly root: string;\n /** Context of package info */\n readonly context: PackageInfoContext;\n /** Dependencies */\n readonly dependencies: PackageInfo[];\n}\n\ninterface PackageJson {\n name: string;\n version: string;\n type: string | undefined;\n dependencies: Record<string, string>;\n devDependencies: Record<string, string>;\n}\n\nconst compiledTplSuffix = \".plj.gz\";\nconst compiledLibSuffix = \".lib.tengo\";\nconst compiledSoftwareSuffix = \".sw.json\";\nconst compiledAssetSuffix = \".as.json\";\nconst compiledWasmSuffix = \".wasm\";\n\n// We need to keep track of dependencies for correct tgo-test CLI utility configuraiton.\n// It is much simpler to do this here, than duplicate all tle logic regarding dependencies\n// in go code.\nconst srcTestSuffix = \".test.tengo\";\n\nconst srcTplSuffix = \".tpl.tengo\";\nconst srcLibSuffix = \".lib.tengo\";\nconst srcSoftwareSuffix = \".sw.json\";\nconst srcAssetSuffix = \".as.json\";\nconst compilableSuffixes = [srcLibSuffix, srcTplSuffix, srcSoftwareSuffix, srcAssetSuffix];\n\n/**\n * Resolves path to package.json file of the given dependency package.\n */\nfunction resolvePackageJsonPackage(root: string, depPackageName: string): string | undefined {\n if (!path.isAbsolute(root)) {\n throw new Error(`Root path must be absolute: ${root}`);\n }\n\n // First approach: resolving package's main entry point and try to find package.json\n // in dir tree upwards.\n let resolved = tryResolve(root, depPackageName);\n if (resolved) {\n let depth = 0;\n do {\n const p = path.join(resolved, \"package.json\");\n if (pathType(p) === \"file\") return p;\n depth++;\n resolved = path.dirname(resolved);\n } while (depth < 7 && path.basename(resolved) !== \"node_modules\");\n }\n\n // Second approach: trying to find package.json in the package dir.\n const resolved2 = tryResolveOrError(root, `${depPackageName}/package.json`);\n if (resolved2.result !== undefined) {\n return resolved2.result;\n }\n\n // Third approach: some packages (wasm-only components) don't expose any\n // import-resolvable entry point — neither a default export nor `./package.json`.\n // pnpm still installs them at <root>/node_modules/<depPackageName>/, so walk\n // the parent chain and check that path directly.\n if (resolved2.err === \"ERR_PACKAGE_PATH_NOT_EXPORTED\") {\n const fromNodeModules = findInNodeModules(root, depPackageName);\n if (fromNodeModules !== undefined) return fromNodeModules;\n // tolerating not-exported package.json for dev dependencies even if no\n // physical node_modules copy is found.\n return undefined;\n }\n throw new Error(\n `Can't resolve package.json for package ${depPackageName ?? \".\"} relative to ${root}`,\n );\n}\n\nfunction findInNodeModules(root: string, depPackageName: string): string | undefined {\n const candidate = path.join(root, \"node_modules\", depPackageName, \"package.json\");\n if (pathType(candidate) === \"file\") return candidate;\n const parent = path.dirname(root);\n if (parent === root) return undefined;\n return findInNodeModules(parent, depPackageName);\n}\n\nexport function resolvePackageJsonRoot(root: string): string {\n if (!path.isAbsolute(root)) {\n throw new Error(`Root path must be absolute: ${root}`);\n }\n\n const p = path.join(root, \"package.json\");\n if (pathType(p) === \"file\") return p;\n throw new Error(`Can't resolve package.json in ${root}`);\n}\n\ntype PackageInfoContext = \"root\" | \"dependency\" | \"devDependency\";\n\n/**\n * Get package info from package.json and all dependencies.\n */\nexport function getPackageInfo(\n root: string,\n logger: winston.Logger,\n context: PackageInfoContext = \"root\",\n): PackageInfo {\n const packageJsonPath = resolvePackageJsonRoot(root);\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()) as PackageJson;\n\n // resolving dependencies\n const depInfos: PackageInfo[] = [];\n\n if (packageJson.dependencies && context !== \"devDependency\") {\n for (const dep of Object.keys(packageJson.dependencies)) {\n const depPackageJson = resolvePackageJsonPackage(root, dep);\n if (depPackageJson === undefined)\n throw new Error(`Can't resolve package.json for dependency ${dep} of ${root}`);\n const depRoot = path.dirname(depPackageJson);\n depInfos.push(getPackageInfo(depRoot, logger, \"dependency\"));\n }\n }\n\n if (packageJson.devDependencies && context === \"root\") {\n for (const dep of Object.keys(packageJson.devDependencies)) {\n const depPackageJson = resolvePackageJsonPackage(root, dep);\n if (depPackageJson === undefined) {\n logger.warn(`Can't resolve package.json for dev dependency ${dep} of ${root}`);\n // tolerating not-exported package.json for dev dependencies\n continue;\n }\n const depRoot = path.dirname(depPackageJson);\n depInfos.push(getPackageInfo(depRoot, logger, \"devDependency\"));\n }\n }\n\n return {\n name: packageJson.name,\n version: packageJson.version,\n type: packageJson.type,\n dependencies: depInfos,\n root,\n context,\n };\n}\n\nfunction resolveLibsDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"lib\");\n}\n\nfunction resolveTemplatesDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"tpl\");\n}\n\nfunction resolveSoftwareDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"software\");\n}\n\nfunction resolveAssetsDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"asset\");\n}\n\nfunction resolveWasmDst(mode: CompileMode, root: string) {\n return path.resolve(root, mode, \"tengo\", \"wasm\");\n}\n\nfunction loadDependencies(\n logger: winston.Logger,\n compiler: TengoTemplateCompiler,\n packageInfo: PackageInfo,\n): void {\n for (const dep of packageInfo.dependencies) loadDependencies(logger, compiler, dep);\n\n if (packageInfo.context === \"root\")\n // we are not reading compiled files for root package\n return;\n\n // we are in package folder\n const libDistFolder = resolveLibsDst(\"dist\", packageInfo.root);\n const tplDistFolder = resolveTemplatesDst(\"dist\", packageInfo.root);\n const softwareDistFolder = resolveSoftwareDst(\"dist\", packageInfo.root);\n const assetDistFolder = resolveAssetsDst(\"dist\", packageInfo.root);\n const wasmDistFolder = resolveWasmDst(\"dist\", packageInfo.root);\n\n const libDistExists = pathType(libDistFolder) === \"dir\";\n const tplDistExists = pathType(tplDistFolder) === \"dir\";\n const softwareDistExists = pathType(softwareDistFolder) === \"dir\";\n const assetDistExists = pathType(assetDistFolder) === \"dir\";\n const wasmDistExists = pathType(wasmDistFolder) === \"dir\";\n const wasmExports = collectWasmExportPaths(packageInfo.root);\n\n if (\n !libDistExists &&\n !tplDistExists &&\n !softwareDistExists &&\n !assetDistExists &&\n !wasmDistExists &&\n wasmExports.length === 0\n )\n // if neither of tengo-specific folders detected, skipping package\n return;\n\n const packageId = { name: packageInfo.name, version: packageInfo.version };\n\n if (libDistExists) {\n loadLibsFromDir(logger, packageId, \"dist\", libDistFolder, compiler);\n }\n\n if (tplDistExists) {\n loadTemplatesFromDir(logger, packageId, \"dist\", tplDistFolder, compiler);\n }\n\n if (softwareDistExists) {\n loadSoftwareFromDir(logger, packageId, \"dist\", softwareDistFolder, compiler);\n }\n\n if (assetDistExists) {\n loadAssetsFromDir(logger, packageId, \"dist\", assetDistFolder, compiler);\n }\n\n if (wasmDistExists) {\n loadWasmFromDir(logger, packageId, \"dist\", wasmDistFolder, compiler);\n }\n\n for (const wasmExport of wasmExports) {\n loadWasmFromExport(logger, packageId, \"dist\", packageInfo.root, wasmExport, compiler);\n }\n}\n\nfunction loadLibsFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledLibSuffix)) throw new Error(`unexpected file in 'lib' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"library\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledLibSuffix.length),\n version: packageId.version,\n };\n const src = parseSourceFile(logger, mode, file, fullName, true);\n compiler.addLib(src);\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n if (src.dependencies.length > 0) {\n logger.debug(\"Dependencies:\");\n for (const dep of src.dependencies) logger.debug(` - ${typedArtifactNameToString(dep)}`);\n }\n }\n}\n\nfunction loadTemplatesFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n // adding templates\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledTplSuffix)) throw new Error(`unexpected file in 'tpl' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"template\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledTplSuffix.length),\n version: packageId.version,\n };\n const tpl = newTemplateFromContent(mode, fullName, fs.readFileSync(file));\n compiler.addTemplate(templateToSource(tpl));\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n }\n}\n\nfunction loadSoftwareFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledSoftwareSuffix))\n throw new Error(`unexpected file in 'software' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"software\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledSoftwareSuffix.length),\n version: packageId.version,\n };\n\n const source = fs.readFileSync(file).toString();\n\n const software = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n compiler.addSoftware(software);\n }\n}\n\nfunction loadAssetsFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledAssetSuffix))\n throw new Error(`unexpected file in 'asset' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"asset\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledAssetSuffix.length),\n version: packageId.version,\n };\n\n const source = fs.readFileSync(file).toString();\n\n const asset = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n compiler.addAsset(asset);\n }\n}\n\nfunction loadWasmFromDir(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n folder: string,\n compiler: TengoTemplateCompiler,\n) {\n for (const f of fs.readdirSync(folder)) {\n const file = path.resolve(folder, f);\n if (!f.endsWith(compiledWasmSuffix))\n throw new Error(`unexpected file in 'wasm' folder: ${file}`);\n const fullName: FullArtifactName = {\n type: \"wasm\",\n pkg: packageId.name,\n id: f.slice(0, f.length - compiledWasmSuffix.length),\n version: packageId.version,\n };\n\n addWasmFile(logger, mode, file, fullName, compiler);\n }\n}\n\ninterface WasmExport {\n id: string;\n /** wasm file path, relative to the package root */\n relPath: string;\n}\n\nfunction loadWasmFromExport(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n packageRoot: string,\n wasmExport: WasmExport,\n compiler: TengoTemplateCompiler,\n) {\n const file = path.resolve(packageRoot, wasmExport.relPath);\n if (pathType(file) !== \"file\") {\n throw new Error(\n `wasm export \"${wasmExport.id}\" points to missing file: ${file} (package ${packageId.name})`,\n );\n }\n const fullName: FullArtifactName = {\n type: \"wasm\",\n pkg: packageId.name,\n id: wasmExport.id,\n version: packageId.version,\n };\n\n addWasmFile(logger, mode, file, fullName, compiler);\n}\n\nfunction addWasmFile(\n logger: winston.Logger,\n mode: CompileMode,\n file: string,\n fullName: FullArtifactName,\n compiler: TengoTemplateCompiler,\n) {\n // wasm bytes are binary, but hashToSource carries strings only. We base64-encode\n // the bytes; the sourceHash is sha256 of the base64 string so it stays consistent\n // with the existing `hashToSource[hash] === stored value` invariant.\n const bytes = fs.readFileSync(file);\n assertWasmFileSize(file, bytes.length, fullName);\n const source = bytes.toString(\"base64\");\n const wasm = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);\n compiler.addWasm(wasm);\n}\n\n/**\n * Discover wasm artifacts declared by a package's `package.json` via the\n * node `exports` conditional-exports map.\n *\n * Convention: a package that wants to ship one or more wasm components to\n * tengo-builder publishes them under a `\"wasm\"` condition keyed by an\n * `exports` subpath. The subpath becomes the wasm artifact id (`.` →\n * `main`, `./foo` → `foo`). Example shape we look for:\n *\n * {\n * \"exports\": {\n * \".\": {\n * \"wasm\": \"./dist/pframes_rs_wasip2.wasm\", // ← discovered\n * \"wit\": \"./wit/world.wit\"\n * },\n * \"./extra\": {\n * \"wasm\": \"./dist/extra.wasm\" // ← discovered as id \"extra\"\n * }\n * }\n * }\n *\n * Why raw traversal instead of Zod / a typed schema:\n * 1. `package.json#exports` is a community convention with no fixed shape\n * — any combination of strings, objects, arrays, and conditions is\n * legal node syntax. A strict schema would either reject valid\n * packages or have to admit `unknown` for half of it anyway.\n * 2. We care about exactly one condition (`wasm`) on subpath entries,\n * not the rest of the exports tree. A targeted walk reads more\n * directly than a schema that re-describes the conditional-exports\n * grammar.\n * 3. Errors here should always mean \"this package contributes no wasm\";\n * never crash the build. Every check returns `[]` or `continue`s.\n *\n * Returns the discovered wasm exports; empty when the file is missing,\n * malformed, has no `exports`, or has no subpath with a `\"wasm\"`\n * condition pointing at a string path.\n */\nfunction collectWasmExportPaths(packageRoot: string): WasmExport[] {\n const packageJsonPath = path.join(packageRoot, \"package.json\");\n if (pathType(packageJsonPath) !== \"file\") return [];\n\n let raw: unknown;\n try {\n raw = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n } catch {\n return [];\n }\n if (typeof raw !== \"object\" || raw === null) return [];\n\n const exportsField = (raw as { exports?: unknown }).exports;\n if (typeof exportsField !== \"object\" || exportsField === null) return [];\n\n const result: WasmExport[] = [];\n for (const [subpath, value] of Object.entries(exportsField as Record<string, unknown>)) {\n if (!subpath.startsWith(\".\")) continue; // skip condition-only entries\n if (typeof value !== \"object\" || value === null) continue;\n const wasmPath = (value as Record<string, unknown>)[wasmExportCondition];\n if (typeof wasmPath !== \"string\") continue;\n const id = subpath === \".\" ? defaultWasmExportId : subpath.replace(/^\\.\\/?/, \"\");\n if (!id) continue;\n result.push({ id, relPath: wasmPath });\n }\n return result;\n}\n\nexport function parseSources(\n logger: winston.Logger,\n packageId: PackageId,\n mode: CompileMode,\n root: string,\n subdir: string,\n): ArtifactSource[] {\n const sources: ArtifactSource[] = [];\n\n for (const f of fs.readdirSync(path.join(root, subdir))) {\n const inRootPath = path.join(subdir, f); // path to item inside given <root>\n const fullPath = path.join(root, inRootPath); // full path to item from CWD (or abs path, if <root> is abs path)\n\n if (pathType(fullPath) === \"dir\") {\n const nested = parseSources(logger, packageId, mode, root, inRootPath);\n sources.push(...nested);\n continue;\n }\n\n // Handling index.lib.tengo files: rename them to <package-name>.lib.tengo\n const artifactName =\n f === \"index.lib.tengo\" ? `${path.dirname(inRootPath)}.lib.tengo` : inRootPath;\n\n const fullName = fullNameFromFileName(packageId, artifactName.replaceAll(path.sep, \".\"));\n if (!fullName) {\n logger.info(`Skipping unknown file type: ${artifactName}`);\n continue; // skip unknown file types\n }\n\n // if (subdir != '') {\n // throw new Error(`Templates and libraries should reside only inside '${root}' dir.\n // You are free to have any file and dirs structure inside '${root}' keeping other files where you want,\n // but regarding ${compilableSuffixes.join(', ')}, the flat file structure is mandatory.`);\n // }\n\n const file = path.resolve(root, inRootPath);\n logger.debug(`Parsing ${fullNameToString(fullName)} from ${file}`);\n const newSrc = parseSourceFile(logger, mode, file, fullName, true);\n if (newSrc.dependencies.length > 0) {\n logger.debug(\"Detected dependencies:\");\n for (const dep of newSrc.dependencies) logger.debug(` - ${typedArtifactNameToString(dep)}`);\n }\n\n sources.push(newSrc);\n }\n\n return sources;\n}\n\nexport function newCompiler(\n logger: winston.Logger,\n packageInfo: PackageInfo,\n mode: CompileMode,\n): TengoTemplateCompiler {\n const compiler = new TengoTemplateCompiler(mode);\n\n // collect all data (templates, libs and software) from dependency tree\n loadDependencies(logger, compiler, packageInfo);\n\n return compiler;\n}\n\nexport function fullNameFromFileName(\n packageId: PackageId,\n artifactName: string,\n): FullArtifactName | null {\n const pkgAndVersion = { pkg: packageId.name, version: packageId.version };\n if (artifactName.endsWith(srcLibSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcLibSuffix.length),\n type: \"library\",\n };\n }\n\n if (artifactName.endsWith(srcTplSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcTplSuffix.length),\n type: \"template\",\n };\n }\n\n if (artifactName.endsWith(srcSoftwareSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcSoftwareSuffix.length),\n type: \"software\",\n };\n }\n\n if (artifactName.endsWith(srcAssetSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcAssetSuffix.length),\n type: \"asset\",\n };\n }\n\n if (artifactName.endsWith(srcTestSuffix)) {\n return {\n ...pkgAndVersion,\n id: artifactName.substring(0, artifactName.length - srcTestSuffix.length),\n type: \"test\",\n };\n }\n\n return null;\n}\n\nexport function compile(\n logger: winston.Logger,\n packageInfo: PackageInfo,\n mode: CompileMode,\n): TemplatesAndLibs {\n const compiler = newCompiler(logger, packageInfo, mode);\n const sources = parseSources(logger, packageInfo, mode, \"src\", \"\");\n\n // checking that we have something to do\n if (sources.length === 0) {\n const lookFor: string[] = [];\n for (const suffix of compilableSuffixes) {\n lookFor.push(`*${suffix}`);\n }\n\n logger.error(`Nothing to compile. Looked for ${lookFor.join(\", \")}`);\n process.exit(1);\n }\n\n // compilation\n logger.info(`Compiling '${mode}'...`);\n const compiled = compiler.compileAndAdd(sources);\n logger.debug(`Done.`);\n\n return compiled;\n}\n\nexport function savePacks(logger: winston.Logger, compiled: TemplatesAndLibs, mode: CompileMode) {\n // writing libs\n if (compiled.libs.length > 0) {\n const libOutput = resolveLibsDst(mode, \".\");\n fs.mkdirSync(libOutput, { recursive: true });\n for (const lib of compiled.libs) {\n const file = path.resolve(libOutput, lib.fullName.id + compiledLibSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, lib.src);\n }\n }\n\n // writing templates\n if (compiled.templates.length > 0) {\n const tplOutput = resolveTemplatesDst(mode, \".\");\n fs.mkdirSync(tplOutput, { recursive: true });\n for (const tpl of compiled.templates) {\n const file = path.resolve(tplOutput, tpl.fullName.id + compiledTplSuffix);\n const packed = serializeTemplate(tpl.data);\n assertTemplatePackSize(\n fullNameToString(tpl.fullName),\n packed.byteLength,\n collectWasmContributions(tpl.data),\n );\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, packed);\n }\n }\n\n // writing software\n if (compiled.software.length > 0) {\n const swOutput = resolveSoftwareDst(mode, \".\");\n fs.mkdirSync(swOutput, { recursive: true });\n for (const sw of compiled.software) {\n const file = path.resolve(swOutput, sw.fullName.id + compiledSoftwareSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, sw.src);\n }\n }\n\n // writing assets\n if (compiled.assets.length > 0) {\n const swOutput = resolveAssetsDst(mode, \".\");\n fs.mkdirSync(swOutput, { recursive: true });\n for (const sw of compiled.software) {\n const file = path.resolve(swOutput, sw.fullName.id + compiledAssetSuffix);\n logger.info(` - writing ${file}`);\n fs.writeFileSync(file, sw.src);\n }\n }\n\n // writing wasm\n if (compiled.wasm.length > 0) {\n const wasmOutput = resolveWasmDst(mode, \".\");\n fs.mkdirSync(wasmOutput, { recursive: true });\n for (const wasm of compiled.wasm) {\n const file = path.resolve(wasmOutput, wasm.fullName.id + compiledWasmSuffix);\n logger.info(` - writing ${file}`);\n // wasm.src holds base64-encoded bytes; decode back to raw bytes on disk\n fs.writeFileSync(file, Buffer.from(wasm.src, \"base64\"));\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAyBA,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AA4B5B,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAK3B,MAAM,gBAAgB;AAEtB,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AACvB,MAAM,qBAAqB;CAAC;CAAc;CAAc;CAAmB;CAAe;;;;AAK1F,SAAS,0BAA0B,MAAc,gBAA4C;AAC3F,KAAI,CAACA,UAAK,WAAW,KAAK,CACxB,OAAM,IAAI,MAAM,+BAA+B,OAAO;CAKxD,IAAI,YAAA,GAAA,+BAAA,YAAsB,MAAM,eAAe;AAC/C,KAAI,UAAU;EACZ,IAAI,QAAQ;AACZ,KAAG;GACD,MAAM,IAAIA,UAAK,KAAK,UAAU,eAAe;AAC7C,OAAIC,aAAAA,SAAS,EAAE,KAAK,OAAQ,QAAO;AACnC;AACA,cAAWD,UAAK,QAAQ,SAAS;WAC1B,QAAQ,KAAKA,UAAK,SAAS,SAAS,KAAK;;CAIpD,MAAM,aAAA,GAAA,+BAAA,mBAA8B,MAAM,GAAG,eAAe,eAAe;AAC3E,KAAI,UAAU,WAAW,KAAA,EACvB,QAAO,UAAU;AAOnB,KAAI,UAAU,QAAQ,iCAAiC;EACrD,MAAM,kBAAkB,kBAAkB,MAAM,eAAe;AAC/D,MAAI,oBAAoB,KAAA,EAAW,QAAO;AAG1C;;AAEF,OAAM,IAAI,MACR,0CAA0C,kBAAkB,IAAI,eAAe,OAChF;;AAGH,SAAS,kBAAkB,MAAc,gBAA4C;CACnF,MAAM,YAAYA,UAAK,KAAK,MAAM,gBAAgB,gBAAgB,eAAe;AACjF,KAAIC,aAAAA,SAAS,UAAU,KAAK,OAAQ,QAAO;CAC3C,MAAM,SAASD,UAAK,QAAQ,KAAK;AACjC,KAAI,WAAW,KAAM,QAAO,KAAA;AAC5B,QAAO,kBAAkB,QAAQ,eAAe;;AAGlD,SAAgB,uBAAuB,MAAsB;AAC3D,KAAI,CAACA,UAAK,WAAW,KAAK,CACxB,OAAM,IAAI,MAAM,+BAA+B,OAAO;CAGxD,MAAM,IAAIA,UAAK,KAAK,MAAM,eAAe;AACzC,KAAIC,aAAAA,SAAS,EAAE,KAAK,OAAQ,QAAO;AACnC,OAAM,IAAI,MAAM,iCAAiC,OAAO;;;;;AAQ1D,SAAgB,eACd,MACA,QACA,UAA8B,QACjB;CACb,MAAM,kBAAkB,uBAAuB,KAAK;CACpD,MAAM,cAAc,KAAK,MAAMC,QAAG,aAAa,gBAAgB,CAAC,UAAU,CAAC;CAG3E,MAAM,WAA0B,EAAE;AAElC,KAAI,YAAY,gBAAgB,YAAY,gBAC1C,MAAK,MAAM,OAAO,OAAO,KAAK,YAAY,aAAa,EAAE;EACvD,MAAM,iBAAiB,0BAA0B,MAAM,IAAI;AAC3D,MAAI,mBAAmB,KAAA,EACrB,OAAM,IAAI,MAAM,6CAA6C,IAAI,MAAM,OAAO;EAChF,MAAM,UAAUF,UAAK,QAAQ,eAAe;AAC5C,WAAS,KAAK,eAAe,SAAS,QAAQ,aAAa,CAAC;;AAIhE,KAAI,YAAY,mBAAmB,YAAY,OAC7C,MAAK,MAAM,OAAO,OAAO,KAAK,YAAY,gBAAgB,EAAE;EAC1D,MAAM,iBAAiB,0BAA0B,MAAM,IAAI;AAC3D,MAAI,mBAAmB,KAAA,GAAW;AAChC,UAAO,KAAK,iDAAiD,IAAI,MAAM,OAAO;AAE9E;;EAEF,MAAM,UAAUA,UAAK,QAAQ,eAAe;AAC5C,WAAS,KAAK,eAAe,SAAS,QAAQ,gBAAgB,CAAC;;AAInE,QAAO;EACL,MAAM,YAAY;EAClB,SAAS,YAAY;EACrB,MAAM,YAAY;EAClB,cAAc;EACd;EACA;EACD;;AAGH,SAAS,eAAe,MAAmB,MAAc;AACvD,QAAOA,UAAK,QAAQ,MAAM,MAAM,SAAS,MAAM;;AAGjD,SAAS,oBAAoB,MAAmB,MAAc;AAC5D,QAAOA,UAAK,QAAQ,MAAM,MAAM,SAAS,MAAM;;AAGjD,SAAS,mBAAmB,MAAmB,MAAc;AAC3D,QAAOA,UAAK,QAAQ,MAAM,MAAM,SAAS,WAAW;;AAGtD,SAAS,iBAAiB,MAAmB,MAAc;AACzD,QAAOA,UAAK,QAAQ,MAAM,MAAM,SAAS,QAAQ;;AAGnD,SAAS,eAAe,MAAmB,MAAc;AACvD,QAAOA,UAAK,QAAQ,MAAM,MAAM,SAAS,OAAO;;AAGlD,SAAS,iBACP,QACA,UACA,aACM;AACN,MAAK,MAAM,OAAO,YAAY,aAAc,kBAAiB,QAAQ,UAAU,IAAI;AAEnF,KAAI,YAAY,YAAY,OAE1B;CAGF,MAAM,gBAAgB,eAAe,QAAQ,YAAY,KAAK;CAC9D,MAAM,gBAAgB,oBAAoB,QAAQ,YAAY,KAAK;CACnE,MAAM,qBAAqB,mBAAmB,QAAQ,YAAY,KAAK;CACvE,MAAM,kBAAkB,iBAAiB,QAAQ,YAAY,KAAK;CAClE,MAAM,iBAAiB,eAAe,QAAQ,YAAY,KAAK;CAE/D,MAAM,gBAAgBC,aAAAA,SAAS,cAAc,KAAK;CAClD,MAAM,gBAAgBA,aAAAA,SAAS,cAAc,KAAK;CAClD,MAAM,qBAAqBA,aAAAA,SAAS,mBAAmB,KAAK;CAC5D,MAAM,kBAAkBA,aAAAA,SAAS,gBAAgB,KAAK;CACtD,MAAM,iBAAiBA,aAAAA,SAAS,eAAe,KAAK;CACpD,MAAM,cAAc,uBAAuB,YAAY,KAAK;AAE5D,KACE,CAAC,iBACD,CAAC,iBACD,CAAC,sBACD,CAAC,mBACD,CAAC,kBACD,YAAY,WAAW,EAGvB;CAEF,MAAM,YAAY;EAAE,MAAM,YAAY;EAAM,SAAS,YAAY;EAAS;AAE1E,KAAI,cACF,iBAAgB,QAAQ,WAAW,QAAQ,eAAe,SAAS;AAGrE,KAAI,cACF,sBAAqB,QAAQ,WAAW,QAAQ,eAAe,SAAS;AAG1E,KAAI,mBACF,qBAAoB,QAAQ,WAAW,QAAQ,oBAAoB,SAAS;AAG9E,KAAI,gBACF,mBAAkB,QAAQ,WAAW,QAAQ,iBAAiB,SAAS;AAGzE,KAAI,eACF,iBAAgB,QAAQ,WAAW,QAAQ,gBAAgB,SAAS;AAGtE,MAAK,MAAM,cAAc,YACvB,oBAAmB,QAAQ,WAAW,QAAQ,YAAY,MAAM,YAAY,SAAS;;AAIzF,SAAS,gBACP,QACA,WACA,MACA,QACA,UACA;AACA,MAAK,MAAM,KAAKC,QAAG,YAAY,OAAO,EAAE;EACtC,MAAM,OAAOF,UAAK,QAAQ,QAAQ,EAAE;AACpC,MAAI,CAAC,EAAE,SAAS,kBAAkB,CAAE,OAAM,IAAI,MAAM,oCAAoC,OAAO;EAC/F,MAAM,WAA6B;GACjC,MAAM;GACN,KAAK,UAAU;GACf,IAAI,EAAE,MAAM,GAAG,EAAE,SAAS,GAAyB;GACnD,SAAS,UAAU;GACpB;EACD,MAAM,MAAMG,eAAAA,gBAAgB,QAAQ,MAAM,MAAM,UAAU,KAAK;AAC/D,WAAS,OAAO,IAAI;AACpB,SAAO,MAAM,qBAAqBC,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,OAAO;AAC5E,MAAI,IAAI,aAAa,SAAS,GAAG;AAC/B,UAAO,MAAM,gBAAgB;AAC7B,QAAK,MAAM,OAAO,IAAI,aAAc,QAAO,MAAM,OAAOC,gBAAAA,0BAA0B,IAAI,GAAG;;;;AAK/F,SAAS,qBACP,QACA,WACA,MACA,QACA,UACA;AAEA,MAAK,MAAM,KAAKH,QAAG,YAAY,OAAO,EAAE;EACtC,MAAM,OAAOF,UAAK,QAAQ,QAAQ,EAAE;AACpC,MAAI,CAAC,EAAE,SAAS,kBAAkB,CAAE,OAAM,IAAI,MAAM,oCAAoC,OAAO;EAC/F,MAAM,WAA6B;GACjC,MAAM;GACN,KAAK,UAAU;GACf,IAAI,EAAE,MAAM,GAAG,EAAE,SAAS,EAAyB;GACnD,SAAS,UAAU;GACpB;EACD,MAAM,MAAMM,iBAAAA,uBAAuB,MAAM,UAAUJ,QAAG,aAAa,KAAK,CAAC;AACzE,WAAS,YAAYK,iBAAAA,iBAAiB,IAAI,CAAC;AAC3C,SAAO,MAAM,qBAAqBH,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,OAAO;;;AAIhF,SAAS,oBACP,QACA,WACA,MACA,QACA,UACA;AACA,MAAK,MAAM,KAAKF,QAAG,YAAY,OAAO,EAAE;EACtC,MAAM,OAAOF,UAAK,QAAQ,QAAQ,EAAE;AACpC,MAAI,CAAC,EAAE,SAAS,uBAAuB,CACrC,OAAM,IAAI,MAAM,yCAAyC,OAAO;EAClE,MAAM,WAA6B;GACjC,MAAM;GACN,KAAK,UAAU;GACf,IAAI,EAAE,MAAM,GAAG,EAAE,SAAS,EAA8B;GACxD,SAAS,UAAU;GACpB;EAED,MAAM,SAASE,QAAG,aAAa,KAAK,CAAC,UAAU;EAE/C,MAAM,WAAW,IAAIM,eAAAA,eAAe,MAAM,UAAUC,eAAAA,UAAU,OAAO,EAAE,QAAQ,MAAM,EAAE,EAAE,EAAE,CAAC;AAE5F,SAAO,MAAM,qBAAqBL,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,OAAO;AAC5E,WAAS,YAAY,SAAS;;;AAIlC,SAAS,kBACP,QACA,WACA,MACA,QACA,UACA;AACA,MAAK,MAAM,KAAKF,QAAG,YAAY,OAAO,EAAE;EACtC,MAAM,OAAOF,UAAK,QAAQ,QAAQ,EAAE;AACpC,MAAI,CAAC,EAAE,SAAS,oBAAoB,CAClC,OAAM,IAAI,MAAM,sCAAsC,OAAO;EAC/D,MAAM,WAA6B;GACjC,MAAM;GACN,KAAK,UAAU;GACf,IAAI,EAAE,MAAM,GAAG,EAAE,SAAS,EAA2B;GACrD,SAAS,UAAU;GACpB;EAED,MAAM,SAASE,QAAG,aAAa,KAAK,CAAC,UAAU;EAE/C,MAAM,QAAQ,IAAIM,eAAAA,eAAe,MAAM,UAAUC,eAAAA,UAAU,OAAO,EAAE,QAAQ,MAAM,EAAE,EAAE,EAAE,CAAC;AAEzF,SAAO,MAAM,qBAAqBL,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,OAAO;AAC5E,WAAS,SAAS,MAAM;;;AAI5B,SAAS,gBACP,QACA,WACA,MACA,QACA,UACA;AACA,MAAK,MAAM,KAAKF,QAAG,YAAY,OAAO,EAAE;EACtC,MAAM,OAAOF,UAAK,QAAQ,QAAQ,EAAE;AACpC,MAAI,CAAC,EAAE,SAAS,mBAAmB,CACjC,OAAM,IAAI,MAAM,qCAAqC,OAAO;AAQ9D,cAAY,QAAQ,MAAM,MAPS;GACjC,MAAM;GACN,KAAK,UAAU;GACf,IAAI,EAAE,MAAM,GAAG,EAAE,SAAS,EAA0B;GACpD,SAAS,UAAU;GACpB,EAEyC,SAAS;;;AAUvD,SAAS,mBACP,QACA,WACA,MACA,aACA,YACA,UACA;CACA,MAAM,OAAOA,UAAK,QAAQ,aAAa,WAAW,QAAQ;AAC1D,KAAIC,aAAAA,SAAS,KAAK,KAAK,OACrB,OAAM,IAAI,MACR,gBAAgB,WAAW,GAAG,4BAA4B,KAAK,YAAY,UAAU,KAAK,GAC3F;AASH,aAAY,QAAQ,MAAM,MAPS;EACjC,MAAM;EACN,KAAK,UAAU;EACf,IAAI,WAAW;EACf,SAAS,UAAU;EACpB,EAEyC,SAAS;;AAGrD,SAAS,YACP,QACA,MACA,MACA,UACA,UACA;CAIA,MAAM,QAAQC,QAAG,aAAa,KAAK;AACnC,qBAAA,mBAAmB,MAAM,MAAM,QAAQ,SAAS;CAChD,MAAM,SAAS,MAAM,SAAS,SAAS;CACvC,MAAM,OAAO,IAAIM,eAAAA,eAAe,MAAM,UAAUC,eAAAA,UAAU,OAAO,EAAE,QAAQ,MAAM,EAAE,EAAE,EAAE,CAAC;AAExF,QAAO,MAAM,qBAAqBL,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,OAAO;AAC5E,UAAS,QAAQ,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCxB,SAAS,uBAAuB,aAAmC;CACjE,MAAM,kBAAkBJ,UAAK,KAAK,aAAa,eAAe;AAC9D,KAAIC,aAAAA,SAAS,gBAAgB,KAAK,OAAQ,QAAO,EAAE;CAEnD,IAAI;AACJ,KAAI;AACF,QAAM,KAAK,MAAMC,QAAG,aAAa,iBAAiB,QAAQ,CAAC;SACrD;AACN,SAAO,EAAE;;AAEX,KAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,EAAE;CAEtD,MAAM,eAAgB,IAA8B;AACpD,KAAI,OAAO,iBAAiB,YAAY,iBAAiB,KAAM,QAAO,EAAE;CAExE,MAAM,SAAuB,EAAE;AAC/B,MAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,aAAwC,EAAE;AACtF,MAAI,CAAC,QAAQ,WAAW,IAAI,CAAE;AAC9B,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM;EACjD,MAAM,WAAY,MAAkC;AACpD,MAAI,OAAO,aAAa,SAAU;EAClC,MAAM,KAAK,YAAY,MAAM,sBAAsB,QAAQ,QAAQ,UAAU,GAAG;AAChF,MAAI,CAAC,GAAI;AACT,SAAO,KAAK;GAAE;GAAI,SAAS;GAAU,CAAC;;AAExC,QAAO;;AAGT,SAAgB,aACd,QACA,WACA,MACA,MACA,QACkB;CAClB,MAAM,UAA4B,EAAE;AAEpC,MAAK,MAAM,KAAKA,QAAG,YAAYF,UAAK,KAAK,MAAM,OAAO,CAAC,EAAE;EACvD,MAAM,aAAaA,UAAK,KAAK,QAAQ,EAAE;AAGvC,MAAIC,aAAAA,SAFaD,UAAK,KAAK,MAAM,WAAW,CAEtB,KAAK,OAAO;GAChC,MAAM,SAAS,aAAa,QAAQ,WAAW,MAAM,MAAM,WAAW;AACtE,WAAQ,KAAK,GAAG,OAAO;AACvB;;EAIF,MAAM,eACJ,MAAM,oBAAoB,GAAGA,UAAK,QAAQ,WAAW,CAAC,cAAc;EAEtE,MAAM,WAAW,qBAAqB,WAAW,aAAa,WAAWA,UAAK,KAAK,IAAI,CAAC;AACxF,MAAI,CAAC,UAAU;AACb,UAAO,KAAK,+BAA+B,eAAe;AAC1D;;EASF,MAAM,OAAOA,UAAK,QAAQ,MAAM,WAAW;AAC3C,SAAO,MAAM,WAAWI,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,OAAO;EAClE,MAAM,SAASD,eAAAA,gBAAgB,QAAQ,MAAM,MAAM,UAAU,KAAK;AAClE,MAAI,OAAO,aAAa,SAAS,GAAG;AAClC,UAAO,MAAM,yBAAyB;AACtC,QAAK,MAAM,OAAO,OAAO,aAAc,QAAO,MAAM,OAAOE,gBAAAA,0BAA0B,IAAI,GAAG;;AAG9F,UAAQ,KAAK,OAAO;;AAGtB,QAAO;;AAGT,SAAgB,YACd,QACA,aACA,MACuB;CACvB,MAAM,WAAW,IAAIK,iBAAAA,sBAAsB,KAAK;AAGhD,kBAAiB,QAAQ,UAAU,YAAY;AAE/C,QAAO;;AAGT,SAAgB,qBACd,WACA,cACyB;CACzB,MAAM,gBAAgB;EAAE,KAAK,UAAU;EAAM,SAAS,UAAU;EAAS;AACzE,KAAI,aAAa,SAAS,aAAa,CACrC,QAAO;EACL,GAAG;EACH,IAAI,aAAa,UAAU,GAAG,aAAa,SAAS,GAAoB;EACxE,MAAM;EACP;AAGH,KAAI,aAAa,SAAS,aAAa,CACrC,QAAO;EACL,GAAG;EACH,IAAI,aAAa,UAAU,GAAG,aAAa,SAAS,GAAoB;EACxE,MAAM;EACP;AAGH,KAAI,aAAa,SAAS,kBAAkB,CAC1C,QAAO;EACL,GAAG;EACH,IAAI,aAAa,UAAU,GAAG,aAAa,SAAS,EAAyB;EAC7E,MAAM;EACP;AAGH,KAAI,aAAa,SAAS,eAAe,CACvC,QAAO;EACL,GAAG;EACH,IAAI,aAAa,UAAU,GAAG,aAAa,SAAS,EAAsB;EAC1E,MAAM;EACP;AAGH,KAAI,aAAa,SAAS,cAAc,CACtC,QAAO;EACL,GAAG;EACH,IAAI,aAAa,UAAU,GAAG,aAAa,SAAS,GAAqB;EACzE,MAAM;EACP;AAGH,QAAO;;AAGT,SAAgB,QACd,QACA,aACA,MACkB;CAClB,MAAM,WAAW,YAAY,QAAQ,aAAa,KAAK;CACvD,MAAM,UAAU,aAAa,QAAQ,aAAa,MAAM,OAAO,GAAG;AAGlE,KAAI,QAAQ,WAAW,GAAG;EACxB,MAAM,UAAoB,EAAE;AAC5B,OAAK,MAAM,UAAU,mBACnB,SAAQ,KAAK,IAAI,SAAS;AAG5B,SAAO,MAAM,kCAAkC,QAAQ,KAAK,KAAK,GAAG;AACpE,UAAQ,KAAK,EAAE;;AAIjB,QAAO,KAAK,cAAc,KAAK,MAAM;CACrC,MAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,QAAO,MAAM,QAAQ;AAErB,QAAO;;AAGT,SAAgB,UAAU,QAAwB,UAA4B,MAAmB;AAE/F,KAAI,SAAS,KAAK,SAAS,GAAG;EAC5B,MAAM,YAAY,eAAe,MAAM,IAAI;AAC3C,UAAG,UAAU,WAAW,EAAE,WAAW,MAAM,CAAC;AAC5C,OAAK,MAAM,OAAO,SAAS,MAAM;GAC/B,MAAM,OAAOV,UAAK,QAAQ,WAAW,IAAI,SAAS,KAAK,kBAAkB;AACzE,UAAO,KAAK,eAAe,OAAO;AAClC,WAAG,cAAc,MAAM,IAAI,IAAI;;;AAKnC,KAAI,SAAS,UAAU,SAAS,GAAG;EACjC,MAAM,YAAY,oBAAoB,MAAM,IAAI;AAChD,UAAG,UAAU,WAAW,EAAE,WAAW,MAAM,CAAC;AAC5C,OAAK,MAAM,OAAO,SAAS,WAAW;GACpC,MAAM,OAAOA,UAAK,QAAQ,WAAW,IAAI,SAAS,KAAK,kBAAkB;GACzE,MAAM,UAAA,GAAA,iCAAA,mBAA2B,IAAI,KAAK;AAC1C,uBAAA,uBACEI,gBAAAA,iBAAiB,IAAI,SAAS,EAC9B,OAAO,YACPO,oBAAAA,yBAAyB,IAAI,KAAK,CACnC;AACD,UAAO,KAAK,eAAe,OAAO;AAClC,WAAG,cAAc,MAAM,OAAO;;;AAKlC,KAAI,SAAS,SAAS,SAAS,GAAG;EAChC,MAAM,WAAW,mBAAmB,MAAM,IAAI;AAC9C,UAAG,UAAU,UAAU,EAAE,WAAW,MAAM,CAAC;AAC3C,OAAK,MAAM,MAAM,SAAS,UAAU;GAClC,MAAM,OAAOX,UAAK,QAAQ,UAAU,GAAG,SAAS,KAAK,uBAAuB;AAC5E,UAAO,KAAK,eAAe,OAAO;AAClC,WAAG,cAAc,MAAM,GAAG,IAAI;;;AAKlC,KAAI,SAAS,OAAO,SAAS,GAAG;EAC9B,MAAM,WAAW,iBAAiB,MAAM,IAAI;AAC5C,UAAG,UAAU,UAAU,EAAE,WAAW,MAAM,CAAC;AAC3C,OAAK,MAAM,MAAM,SAAS,UAAU;GAClC,MAAM,OAAOA,UAAK,QAAQ,UAAU,GAAG,SAAS,KAAK,oBAAoB;AACzE,UAAO,KAAK,eAAe,OAAO;AAClC,WAAG,cAAc,MAAM,GAAG,IAAI;;;AAKlC,KAAI,SAAS,KAAK,SAAS,GAAG;EAC5B,MAAM,aAAa,eAAe,MAAM,IAAI;AAC5C,UAAG,UAAU,YAAY,EAAE,WAAW,MAAM,CAAC;AAC7C,OAAK,MAAM,QAAQ,SAAS,MAAM;GAChC,MAAM,OAAOA,UAAK,QAAQ,YAAY,KAAK,SAAS,KAAK,mBAAmB;AAC5E,UAAO,KAAK,eAAe,OAAO;AAElC,WAAG,cAAc,MAAM,OAAO,KAAK,KAAK,KAAK,SAAS,CAAC"}
@@ -3,15 +3,19 @@ import { fullNameToString, typedArtifactNameToString } from "./package.js";
3
3
  import { newTemplateFromContent, templateToSource } from "./template.js";
4
4
  import { TengoTemplateCompiler } from "./compiler.js";
5
5
  import { ArtifactSource, getSha256, parseSourceFile } from "./source.js";
6
+ import { assertTemplatePackSize, assertWasmFileSize, collectWasmContributions } from "./pack_limits.js";
6
7
  import * as path from "node:path";
7
8
  import * as fs from "node:fs";
8
9
  import { serializeTemplate } from "@milaboratories/pl-model-backend";
9
10
  import { tryResolve, tryResolveOrError } from "@milaboratories/resolve-helper";
10
11
  //#region src/compiler/main.ts
12
+ const wasmExportCondition = "wasm";
13
+ const defaultWasmExportId = "main";
11
14
  const compiledTplSuffix = ".plj.gz";
12
15
  const compiledLibSuffix = ".lib.tengo";
13
16
  const compiledSoftwareSuffix = ".sw.json";
14
17
  const compiledAssetSuffix = ".as.json";
18
+ const compiledWasmSuffix = ".wasm";
15
19
  const srcTestSuffix = ".test.tengo";
16
20
  const srcTplSuffix = ".tpl.tengo";
17
21
  const srcLibSuffix = ".lib.tengo";
@@ -39,11 +43,20 @@ function resolvePackageJsonPackage(root, depPackageName) {
39
43
  } while (depth < 7 && path.basename(resolved) !== "node_modules");
40
44
  }
41
45
  const resolved2 = tryResolveOrError(root, `${depPackageName}/package.json`);
42
- if (resolved2.result === void 0) {
43
- if (resolved2.err === "ERR_PACKAGE_PATH_NOT_EXPORTED") return void 0;
44
- throw new Error(`Can't resolve package.json for package ${depPackageName ?? "."} relative to ${root}`);
46
+ if (resolved2.result !== void 0) return resolved2.result;
47
+ if (resolved2.err === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
48
+ const fromNodeModules = findInNodeModules(root, depPackageName);
49
+ if (fromNodeModules !== void 0) return fromNodeModules;
50
+ return;
45
51
  }
46
- return resolved2.result;
52
+ throw new Error(`Can't resolve package.json for package ${depPackageName ?? "."} relative to ${root}`);
53
+ }
54
+ function findInNodeModules(root, depPackageName) {
55
+ const candidate = path.join(root, "node_modules", depPackageName, "package.json");
56
+ if (pathType(candidate) === "file") return candidate;
57
+ const parent = path.dirname(root);
58
+ if (parent === root) return void 0;
59
+ return findInNodeModules(parent, depPackageName);
47
60
  }
48
61
  function resolvePackageJsonRoot(root) {
49
62
  if (!path.isAbsolute(root)) throw new Error(`Root path must be absolute: ${root}`);
@@ -94,6 +107,9 @@ function resolveSoftwareDst(mode, root) {
94
107
  function resolveAssetsDst(mode, root) {
95
108
  return path.resolve(root, mode, "tengo", "asset");
96
109
  }
110
+ function resolveWasmDst(mode, root) {
111
+ return path.resolve(root, mode, "tengo", "wasm");
112
+ }
97
113
  function loadDependencies(logger, compiler, packageInfo) {
98
114
  for (const dep of packageInfo.dependencies) loadDependencies(logger, compiler, dep);
99
115
  if (packageInfo.context === "root") return;
@@ -101,11 +117,14 @@ function loadDependencies(logger, compiler, packageInfo) {
101
117
  const tplDistFolder = resolveTemplatesDst("dist", packageInfo.root);
102
118
  const softwareDistFolder = resolveSoftwareDst("dist", packageInfo.root);
103
119
  const assetDistFolder = resolveAssetsDst("dist", packageInfo.root);
120
+ const wasmDistFolder = resolveWasmDst("dist", packageInfo.root);
104
121
  const libDistExists = pathType(libDistFolder) === "dir";
105
122
  const tplDistExists = pathType(tplDistFolder) === "dir";
106
123
  const softwareDistExists = pathType(softwareDistFolder) === "dir";
107
124
  const assetDistExists = pathType(assetDistFolder) === "dir";
108
- if (!libDistExists && !tplDistExists && !softwareDistExists && !assetDistExists) return;
125
+ const wasmDistExists = pathType(wasmDistFolder) === "dir";
126
+ const wasmExports = collectWasmExportPaths(packageInfo.root);
127
+ if (!libDistExists && !tplDistExists && !softwareDistExists && !assetDistExists && !wasmDistExists && wasmExports.length === 0) return;
109
128
  const packageId = {
110
129
  name: packageInfo.name,
111
130
  version: packageInfo.version
@@ -114,6 +133,8 @@ function loadDependencies(logger, compiler, packageInfo) {
114
133
  if (tplDistExists) loadTemplatesFromDir(logger, packageId, "dist", tplDistFolder, compiler);
115
134
  if (softwareDistExists) loadSoftwareFromDir(logger, packageId, "dist", softwareDistFolder, compiler);
116
135
  if (assetDistExists) loadAssetsFromDir(logger, packageId, "dist", assetDistFolder, compiler);
136
+ if (wasmDistExists) loadWasmFromDir(logger, packageId, "dist", wasmDistFolder, compiler);
137
+ for (const wasmExport of wasmExports) loadWasmFromExport(logger, packageId, "dist", packageInfo.root, wasmExport, compiler);
117
138
  }
118
139
  function loadLibsFromDir(logger, packageId, mode, folder, compiler) {
119
140
  for (const f of fs.readdirSync(folder)) {
@@ -181,6 +202,100 @@ function loadAssetsFromDir(logger, packageId, mode, folder, compiler) {
181
202
  compiler.addAsset(asset);
182
203
  }
183
204
  }
205
+ function loadWasmFromDir(logger, packageId, mode, folder, compiler) {
206
+ for (const f of fs.readdirSync(folder)) {
207
+ const file = path.resolve(folder, f);
208
+ if (!f.endsWith(compiledWasmSuffix)) throw new Error(`unexpected file in 'wasm' folder: ${file}`);
209
+ addWasmFile(logger, mode, file, {
210
+ type: "wasm",
211
+ pkg: packageId.name,
212
+ id: f.slice(0, f.length - 5),
213
+ version: packageId.version
214
+ }, compiler);
215
+ }
216
+ }
217
+ function loadWasmFromExport(logger, packageId, mode, packageRoot, wasmExport, compiler) {
218
+ const file = path.resolve(packageRoot, wasmExport.relPath);
219
+ if (pathType(file) !== "file") throw new Error(`wasm export "${wasmExport.id}" points to missing file: ${file} (package ${packageId.name})`);
220
+ addWasmFile(logger, mode, file, {
221
+ type: "wasm",
222
+ pkg: packageId.name,
223
+ id: wasmExport.id,
224
+ version: packageId.version
225
+ }, compiler);
226
+ }
227
+ function addWasmFile(logger, mode, file, fullName, compiler) {
228
+ const bytes = fs.readFileSync(file);
229
+ assertWasmFileSize(file, bytes.length, fullName);
230
+ const source = bytes.toString("base64");
231
+ const wasm = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);
232
+ logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
233
+ compiler.addWasm(wasm);
234
+ }
235
+ /**
236
+ * Discover wasm artifacts declared by a package's `package.json` via the
237
+ * node `exports` conditional-exports map.
238
+ *
239
+ * Convention: a package that wants to ship one or more wasm components to
240
+ * tengo-builder publishes them under a `"wasm"` condition keyed by an
241
+ * `exports` subpath. The subpath becomes the wasm artifact id (`.` →
242
+ * `main`, `./foo` → `foo`). Example shape we look for:
243
+ *
244
+ * {
245
+ * "exports": {
246
+ * ".": {
247
+ * "wasm": "./dist/pframes_rs_wasip2.wasm", // ← discovered
248
+ * "wit": "./wit/world.wit"
249
+ * },
250
+ * "./extra": {
251
+ * "wasm": "./dist/extra.wasm" // ← discovered as id "extra"
252
+ * }
253
+ * }
254
+ * }
255
+ *
256
+ * Why raw traversal instead of Zod / a typed schema:
257
+ * 1. `package.json#exports` is a community convention with no fixed shape
258
+ * — any combination of strings, objects, arrays, and conditions is
259
+ * legal node syntax. A strict schema would either reject valid
260
+ * packages or have to admit `unknown` for half of it anyway.
261
+ * 2. We care about exactly one condition (`wasm`) on subpath entries,
262
+ * not the rest of the exports tree. A targeted walk reads more
263
+ * directly than a schema that re-describes the conditional-exports
264
+ * grammar.
265
+ * 3. Errors here should always mean "this package contributes no wasm";
266
+ * never crash the build. Every check returns `[]` or `continue`s.
267
+ *
268
+ * Returns the discovered wasm exports; empty when the file is missing,
269
+ * malformed, has no `exports`, or has no subpath with a `"wasm"`
270
+ * condition pointing at a string path.
271
+ */
272
+ function collectWasmExportPaths(packageRoot) {
273
+ const packageJsonPath = path.join(packageRoot, "package.json");
274
+ if (pathType(packageJsonPath) !== "file") return [];
275
+ let raw;
276
+ try {
277
+ raw = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
278
+ } catch {
279
+ return [];
280
+ }
281
+ if (typeof raw !== "object" || raw === null) return [];
282
+ const exportsField = raw.exports;
283
+ if (typeof exportsField !== "object" || exportsField === null) return [];
284
+ const result = [];
285
+ for (const [subpath, value] of Object.entries(exportsField)) {
286
+ if (!subpath.startsWith(".")) continue;
287
+ if (typeof value !== "object" || value === null) continue;
288
+ const wasmPath = value[wasmExportCondition];
289
+ if (typeof wasmPath !== "string") continue;
290
+ const id = subpath === "." ? defaultWasmExportId : subpath.replace(/^\.\/?/, "");
291
+ if (!id) continue;
292
+ result.push({
293
+ id,
294
+ relPath: wasmPath
295
+ });
296
+ }
297
+ return result;
298
+ }
184
299
  function parseSources(logger, packageId, mode, root, subdir) {
185
300
  const sources = [];
186
301
  for (const f of fs.readdirSync(path.join(root, subdir))) {
@@ -273,8 +388,10 @@ function savePacks(logger, compiled, mode) {
273
388
  fs.mkdirSync(tplOutput, { recursive: true });
274
389
  for (const tpl of compiled.templates) {
275
390
  const file = path.resolve(tplOutput, tpl.fullName.id + compiledTplSuffix);
391
+ const packed = serializeTemplate(tpl.data);
392
+ assertTemplatePackSize(fullNameToString(tpl.fullName), packed.byteLength, collectWasmContributions(tpl.data));
276
393
  logger.info(` - writing ${file}`);
277
- fs.writeFileSync(file, serializeTemplate(tpl.data));
394
+ fs.writeFileSync(file, packed);
278
395
  }
279
396
  }
280
397
  if (compiled.software.length > 0) {
@@ -295,6 +412,15 @@ function savePacks(logger, compiled, mode) {
295
412
  fs.writeFileSync(file, sw.src);
296
413
  }
297
414
  }
415
+ if (compiled.wasm.length > 0) {
416
+ const wasmOutput = resolveWasmDst(mode, ".");
417
+ fs.mkdirSync(wasmOutput, { recursive: true });
418
+ for (const wasm of compiled.wasm) {
419
+ const file = path.resolve(wasmOutput, wasm.fullName.id + compiledWasmSuffix);
420
+ logger.info(` - writing ${file}`);
421
+ fs.writeFileSync(file, Buffer.from(wasm.src, "base64"));
422
+ }
423
+ }
298
424
  }
299
425
  //#endregion
300
426
  export { compile, getPackageInfo, newCompiler, parseSources, savePacks };