@platforma-sdk/tengo-builder 4.0.1 → 4.0.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.
@@ -9,6 +9,8 @@ let node_path = require("node:path");
9
9
  node_path = require_runtime.__toESM(node_path);
10
10
  let node_fs = require("node:fs");
11
11
  node_fs = require_runtime.__toESM(node_fs);
12
+ let node_zlib = require("node:zlib");
13
+ node_zlib = require_runtime.__toESM(node_zlib);
12
14
  let _milaboratories_pl_model_backend = require("@milaboratories/pl-model-backend");
13
15
  let _milaboratories_resolve_helper = require("@milaboratories/resolve-helper");
14
16
  //#region src/compiler/main.ts
@@ -228,11 +230,12 @@ function loadWasmFromExport(logger, packageId, mode, packageRoot, wasmExport, co
228
230
  }, compiler);
229
231
  }
230
232
  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");
233
+ const raw = node_fs.readFileSync(file);
234
+ const compressed = node_zlib.gzipSync(raw, { level: node_zlib.constants.Z_BEST_COMPRESSION });
235
+ require_pack_limits.assertWasmFileSize(file, compressed.length, fullName);
236
+ const source = compressed.toString("base64");
234
237
  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}`);
238
+ logger.debug(`Adding dependency ${require_package.fullNameToString(fullName)} from ${file} (${raw.length} B raw → ${compressed.length} B gzipped)`);
236
239
  compiler.addWasm(wasm);
237
240
  }
238
241
  /**
@@ -1 +1 @@
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":"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"}
1
+ {"version":3,"file":"main.cjs","names":["path","pathType","fs","parseSourceFile","fullNameToString","typedArtifactNameToString","newTemplateFromContent","templateToSource","ArtifactSource","getSha256","zlib","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 * as zlib from \"node:zlib\";\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. The file is\n // gzipped first (level 9 — block builds run rarely, so paying the slow-but-\n // tight setting is fine) and then base64-encoded. The backend's wasm package\n // sniffs the gzip header at PrecompileComponent time and gunzips before\n // handing the bytes to wasmtime. Compressing here shrinks both the per-WASM\n // resource footprint (a real wasm component compresses to ~30-40 % of its\n // raw size) and the on-wire pack, which lets pframes-rs grow past the\n // 3 MiB raw-size ceiling without hitting the backend's value-resource cap.\n const raw = fs.readFileSync(file);\n const compressed = zlib.gzipSync(raw, { level: zlib.constants.Z_BEST_COMPRESSION });\n assertWasmFileSize(file, compressed.length, fullName);\n const source = compressed.toString(\"base64\");\n const wasm = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(\n `Adding dependency ${fullNameToString(fullName)} from ${file} ` +\n `(${raw.length} B raw → ${compressed.length} B gzipped)`,\n );\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":"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"}
@@ -6,6 +6,7 @@ import { ArtifactSource, getSha256, parseSourceFile } from "./source.js";
6
6
  import { assertTemplatePackSize, assertWasmFileSize, collectWasmContributions } from "./pack_limits.js";
7
7
  import * as path from "node:path";
8
8
  import * as fs from "node:fs";
9
+ import * as zlib from "node:zlib";
9
10
  import { serializeTemplate } from "@milaboratories/pl-model-backend";
10
11
  import { tryResolve, tryResolveOrError } from "@milaboratories/resolve-helper";
11
12
  //#region src/compiler/main.ts
@@ -225,11 +226,12 @@ function loadWasmFromExport(logger, packageId, mode, packageRoot, wasmExport, co
225
226
  }, compiler);
226
227
  }
227
228
  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");
229
+ const raw = fs.readFileSync(file);
230
+ const compressed = zlib.gzipSync(raw, { level: zlib.constants.Z_BEST_COMPRESSION });
231
+ assertWasmFileSize(file, compressed.length, fullName);
232
+ const source = compressed.toString("base64");
231
233
  const wasm = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);
232
- logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
234
+ logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file} (${raw.length} B raw → ${compressed.length} B gzipped)`);
233
235
  compiler.addWasm(wasm);
234
236
  }
235
237
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":[],"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":"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"}
1
+ {"version":3,"file":"main.js","names":[],"sources":["../../src/compiler/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport * as path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport * as zlib from \"node:zlib\";\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. The file is\n // gzipped first (level 9 — block builds run rarely, so paying the slow-but-\n // tight setting is fine) and then base64-encoded. The backend's wasm package\n // sniffs the gzip header at PrecompileComponent time and gunzips before\n // handing the bytes to wasmtime. Compressing here shrinks both the per-WASM\n // resource footprint (a real wasm component compresses to ~30-40 % of its\n // raw size) and the on-wire pack, which lets pframes-rs grow past the\n // 3 MiB raw-size ceiling without hitting the backend's value-resource cap.\n const raw = fs.readFileSync(file);\n const compressed = zlib.gzipSync(raw, { level: zlib.constants.Z_BEST_COMPRESSION });\n assertWasmFileSize(file, compressed.length, fullName);\n const source = compressed.toString(\"base64\");\n const wasm = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);\n\n logger.debug(\n `Adding dependency ${fullNameToString(fullName)} from ${file} ` +\n `(${raw.length} B raw → ${compressed.length} B gzipped)`,\n );\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":"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"}
@@ -9,7 +9,7 @@ function formatBytes(n) {
9
9
  }
10
10
  function assertWasmFileSize(file, byteLength, fullName) {
11
11
  if (byteLength <= 2097152) return;
12
- throw new Error(`WASM artefact ${require_package.fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)}, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). Strip debug info or run \`wasm-opt -Oz\` to shrink it.`);
12
+ throw new Error(`WASM artefact ${require_package.fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)} gzipped, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). Strip debug info or run \`wasm-opt -Oz\` to shrink it.`);
13
13
  }
14
14
  /**
15
15
  * Walks a compiled template tree and reports every WASM artefact embedded
@@ -24,10 +24,10 @@ function collectWasmContributions(tpl) {
24
24
  for (const [name, ref] of Object.entries(t.wasm ?? {})) {
25
25
  if (seen.has(name)) continue;
26
26
  const base64 = tpl.hashToSource[ref.sourceHash];
27
- const rawBytes = base64 != null ? Math.floor(base64.length * 3 / 4) : 0;
27
+ const storedBytes = base64 != null ? Math.floor(base64.length * 3 / 4) : 0;
28
28
  seen.set(name, {
29
29
  name,
30
- rawBytes
30
+ storedBytes
31
31
  });
32
32
  }
33
33
  for (const sub of Object.values(t.templates ?? {})) walk(sub);
@@ -37,8 +37,8 @@ function collectWasmContributions(tpl) {
37
37
  }
38
38
  function assertTemplatePackSize(templateName, gzippedByteLength, wasmContributions) {
39
39
  if (gzippedByteLength <= 3567616) return;
40
- const ranked = [...wasmContributions].sort((a, b) => b.rawBytes - a.rawBytes);
41
- const breakdown = ranked.length === 0 ? "\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)" : "\nWASM artefacts in this pack (raw bytes):\n" + ranked.map((w) => ` - ${w.name} — ${formatBytes(w.rawBytes)}`).join("\n");
40
+ const ranked = [...wasmContributions].sort((a, b) => b.storedBytes - a.storedBytes);
41
+ const breakdown = ranked.length === 0 ? "\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)" : "\nWASM artefacts in this pack (gzipped, pre-base64):\n" + ranked.map((w) => ` - ${w.name} — ${formatBytes(w.storedBytes)}`).join("\n");
42
42
  throw new Error(`Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. The backend caps gzipped packs at 3.5 MiB (see TemplatePackSizeLimit in pl: controllers/workflow/pkg/cfg/config.go).` + breakdown + "\nShrink WASM artefacts (wasm-opt -Oz), or split this template into smaller pieces.");
43
43
  }
44
44
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"pack_limits.cjs","names":["fullNameToString"],"sources":["../../src/compiler/pack_limits.ts"],"sourcesContent":["import type { CompiledTemplateV3, TemplateDataV3 } from \"@milaboratories/pl-model-backend\";\n\nimport type { FullArtifactName } from \"./package\";\nimport { fullNameToString } from \"./package\";\n\n// Build-time size guards mirroring the two backend caps that gate template\n// ingestion. Hardcoded because tengo-builder runs at block build time and has\n// no connection to a running backend; if pl ever changes the caps, update the\n// constants here in lockstep with the source-of-truth lines pointed at below.\n//\n// Source of truth (`core/pl` repo):\n// - platform/core/transaction/assertions.go : `maxResourceDataSize`\n// 3 MiB per value resource, checked on every CreateValue marshal.\n// Hits the WasmV1 resource after the controller unpacks a template pack\n// into its constituent libs/software/wasm resources.\n// - controllers/workflow/pkg/cfg/config.go : `TemplatePackSizeLimit`\n// 3.5 MiB per gzipped template pack, checked before the pack itself is\n// stored as a TengoTemplatePackV1 value resource.\n\n// 2 MiB raw → ~2.67 MiB base64 + JSON wrapper → comfortably under the 3 MiB\n// per-value-resource cap with ~330 KiB headroom for the WasmV1Data wrapper\n// (Name, Version, Runtime, DefaultMemoryLimit, JSON syntax). WasmV1Data.Code\n// is a Go `[]byte`, which encoding/json serialises as base64 — that's where\n// the 4/3 expansion comes from.\nexport const MAX_WASM_FILE_BYTES = 2 * 1024 * 1024;\n\n// 100 KiB below the backend's 3.5 MiB so blocks don't break on small\n// platform-side metadata overhead, or if pl tightens the limit slightly.\nexport const MAX_TEMPLATE_PACK_BYTES_GZIPPED = 3.5 * 1024 * 1024 - 100 * 1024;\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`;\n return `${(n / 1024 / 1024).toFixed(2)} MiB`;\n}\n\nexport function assertWasmFileSize(\n file: string,\n byteLength: number,\n fullName: FullArtifactName,\n): void {\n if (byteLength <= MAX_WASM_FILE_BYTES) return;\n throw new Error(\n `WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)}, ` +\n `which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. ` +\n `The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON ` +\n `marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). ` +\n `Strip debug info or run \\`wasm-opt -Oz\\` to shrink it.`,\n );\n}\n\nexport interface WasmContribution {\n /** Artefact name as stored under TemplateDataV3.wasm (e.g. \"@pkg:id\"). */\n readonly name: string;\n /** Raw WASM bytes — decoded from the base64-encoded source in hashToSource. */\n readonly rawBytes: number;\n}\n\n/**\n * Walks a compiled template tree and reports every WASM artefact embedded\n * directly or transitively. Used only by the too-large-pack error message —\n * never on the success path. Deduplicates by artefact name (sub-templates can\n * import the same WASM via different aliases and we want to attribute weight\n * only once).\n */\nexport function collectWasmContributions(tpl: CompiledTemplateV3): WasmContribution[] {\n const seen = new Map<string, WasmContribution>();\n function walk(t: TemplateDataV3) {\n for (const [name, ref] of Object.entries(t.wasm ?? {})) {\n if (seen.has(name)) continue;\n const base64 = tpl.hashToSource[ref.sourceHash];\n // base64 encodes 3 raw bytes per 4 chars; the off-by-padding is at most\n // 2 bytes per artefact — fine for a human-readable size breakdown.\n const rawBytes = base64 != null ? Math.floor((base64.length * 3) / 4) : 0;\n seen.set(name, { name, rawBytes });\n }\n for (const sub of Object.values(t.templates ?? {})) walk(sub);\n }\n walk(tpl.template);\n return [...seen.values()];\n}\n\nexport function assertTemplatePackSize(\n templateName: string,\n gzippedByteLength: number,\n wasmContributions: readonly WasmContribution[],\n): void {\n if (gzippedByteLength <= MAX_TEMPLATE_PACK_BYTES_GZIPPED) return;\n const ranked = [...wasmContributions].sort((a, b) => b.rawBytes - a.rawBytes);\n const breakdown =\n ranked.length === 0\n ? \"\\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)\"\n : \"\\nWASM artefacts in this pack (raw bytes):\\n\" +\n ranked.map((w) => ` - ${w.name} — ${formatBytes(w.rawBytes)}`).join(\"\\n\");\n throw new Error(\n `Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, ` +\n `which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. ` +\n `The backend caps gzipped packs at 3.5 MiB (see TemplatePackSizeLimit in pl: ` +\n `controllers/workflow/pkg/cfg/config.go).` +\n breakdown +\n \"\\nShrink WASM artefacts (wasm-opt -Oz), or split this template into smaller pieces.\",\n );\n}\n"],"mappings":";;AAwBA,MAAa,sBAAsB,IAAI,OAAO;AAI9C,MAAa,kCAAkC,MAAM,OAAO,OAAO,MAAM;AAEzE,SAAS,YAAY,GAAmB;AACtC,KAAI,IAAI,KAAM,QAAO,GAAG,EAAE;AAC1B,KAAI,IAAI,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,QAAQ,EAAE,CAAC;AACrD,QAAO,IAAI,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC;;AAGzC,SAAgB,mBACd,MACA,YACA,UACM;AACN,KAAI,cAAA,QAAmC;AACvC,OAAM,IAAI,MACR,iBAAiBA,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,KAAK,MAAM,YAAY,WAAW,CAAC,kCACpD,YAAY,oBAAoB,CAAC,oPAIrE;;;;;;;;;AAiBH,SAAgB,yBAAyB,KAA6C;CACpF,MAAM,uBAAO,IAAI,KAA+B;CAChD,SAAS,KAAK,GAAmB;AAC/B,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE;AACtD,OAAI,KAAK,IAAI,KAAK,CAAE;GACpB,MAAM,SAAS,IAAI,aAAa,IAAI;GAGpC,MAAM,WAAW,UAAU,OAAO,KAAK,MAAO,OAAO,SAAS,IAAK,EAAE,GAAG;AACxE,QAAK,IAAI,MAAM;IAAE;IAAM;IAAU,CAAC;;AAEpC,OAAK,MAAM,OAAO,OAAO,OAAO,EAAE,aAAa,EAAE,CAAC,CAAE,MAAK,IAAI;;AAE/D,MAAK,IAAI,SAAS;AAClB,QAAO,CAAC,GAAG,KAAK,QAAQ,CAAC;;AAG3B,SAAgB,uBACd,cACA,mBACA,mBACM;AACN,KAAI,qBAAA,QAAsD;CAC1D,MAAM,SAAS,CAAC,GAAG,kBAAkB,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;CAC7E,MAAM,YACJ,OAAO,WAAW,IACd,oHACA,iDACA,OAAO,KAAK,MAAM,OAAO,EAAE,KAAK,KAAK,YAAY,EAAE,SAAS,GAAG,CAAC,KAAK,KAAK;AAChF,OAAM,IAAI,MACR,iBAAiB,aAAa,MAAM,YAAY,kBAAkB,CAAC,0CAChC,YAAY,gCAAgC,CAAC,uIAG9E,YACA,sFACH"}
1
+ {"version":3,"file":"pack_limits.cjs","names":["fullNameToString"],"sources":["../../src/compiler/pack_limits.ts"],"sourcesContent":["import type { CompiledTemplateV3, TemplateDataV3 } from \"@milaboratories/pl-model-backend\";\n\nimport type { FullArtifactName } from \"./package\";\nimport { fullNameToString } from \"./package\";\n\n// Build-time size guards mirroring the two backend caps that gate template\n// ingestion. Hardcoded because tengo-builder runs at block build time and has\n// no connection to a running backend; if pl ever changes the caps, update the\n// constants here in lockstep with the source-of-truth lines pointed at below.\n//\n// Source of truth (`core/pl` repo):\n// - platform/core/transaction/assertions.go : `maxResourceDataSize`\n// 3 MiB per value resource, checked on every CreateValue marshal.\n// Hits the WasmV1 resource after the controller unpacks a template pack\n// into its constituent libs/software/wasm resources.\n// - controllers/workflow/pkg/cfg/config.go : `TemplatePackSizeLimit`\n// 3.5 MiB per gzipped template pack, checked before the pack itself is\n// stored as a TengoTemplatePackV1 value resource.\n\n// Cap on the gzipped wasm payload that ends up in WasmV1Data.Code on the\n// backend. 2 MiB gzipped → ~2.67 MiB base64 + JSON wrapper → comfortably\n// under the 3 MiB per-value-resource cap with ~330 KiB headroom for the\n// WasmV1Data wrapper (Name, Version, Runtime, DefaultMemoryLimit, JSON\n// syntax). WasmV1Data.Code is a Go `[]byte`, which encoding/json serialises\n// as base64 — that's where the 4/3 expansion comes from.\n//\n// The tengo-builder gzips wasm files before adding them to the pack; this\n// cap therefore admits raw .wasm files several times larger than 2 MiB\n// (real wasm components compress to ~30-40 % of their raw size).\nexport const MAX_WASM_FILE_BYTES = 2 * 1024 * 1024;\n\n// 100 KiB below the backend's 3.5 MiB so blocks don't break on small\n// platform-side metadata overhead, or if pl tightens the limit slightly.\nexport const MAX_TEMPLATE_PACK_BYTES_GZIPPED = 3.5 * 1024 * 1024 - 100 * 1024;\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`;\n return `${(n / 1024 / 1024).toFixed(2)} MiB`;\n}\n\nexport function assertWasmFileSize(\n file: string,\n byteLength: number,\n fullName: FullArtifactName,\n): void {\n if (byteLength <= MAX_WASM_FILE_BYTES) return;\n throw new Error(\n `WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)} ` +\n `gzipped, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. ` +\n `The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON ` +\n `marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). ` +\n `Strip debug info or run \\`wasm-opt -Oz\\` to shrink it.`,\n );\n}\n\nexport interface WasmContribution {\n /** Artefact name as stored under TemplateDataV3.wasm (e.g. \"@pkg:id\"). */\n readonly name: string;\n /**\n * Bytes this artefact contributes to the pack, measured after gzip and\n * before base64 — i.e. the size of the binary payload stored on the\n * backend in WasmV1Data.Code. Decoded from the base64-encoded source in\n * hashToSource.\n */\n readonly storedBytes: number;\n}\n\n/**\n * Walks a compiled template tree and reports every WASM artefact embedded\n * directly or transitively. Used only by the too-large-pack error message —\n * never on the success path. Deduplicates by artefact name (sub-templates can\n * import the same WASM via different aliases and we want to attribute weight\n * only once).\n */\nexport function collectWasmContributions(tpl: CompiledTemplateV3): WasmContribution[] {\n const seen = new Map<string, WasmContribution>();\n function walk(t: TemplateDataV3) {\n for (const [name, ref] of Object.entries(t.wasm ?? {})) {\n if (seen.has(name)) continue;\n const base64 = tpl.hashToSource[ref.sourceHash];\n // base64 encodes 3 binary bytes per 4 chars; the off-by-padding is at\n // most 2 bytes per artefact — fine for a human-readable size breakdown.\n const storedBytes = base64 != null ? Math.floor((base64.length * 3) / 4) : 0;\n seen.set(name, { name, storedBytes });\n }\n for (const sub of Object.values(t.templates ?? {})) walk(sub);\n }\n walk(tpl.template);\n return [...seen.values()];\n}\n\nexport function assertTemplatePackSize(\n templateName: string,\n gzippedByteLength: number,\n wasmContributions: readonly WasmContribution[],\n): void {\n if (gzippedByteLength <= MAX_TEMPLATE_PACK_BYTES_GZIPPED) return;\n const ranked = [...wasmContributions].sort((a, b) => b.storedBytes - a.storedBytes);\n const breakdown =\n ranked.length === 0\n ? \"\\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)\"\n : \"\\nWASM artefacts in this pack (gzipped, pre-base64):\\n\" +\n ranked.map((w) => ` - ${w.name} — ${formatBytes(w.storedBytes)}`).join(\"\\n\");\n throw new Error(\n `Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, ` +\n `which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. ` +\n `The backend caps gzipped packs at 3.5 MiB (see TemplatePackSizeLimit in pl: ` +\n `controllers/workflow/pkg/cfg/config.go).` +\n breakdown +\n \"\\nShrink WASM artefacts (wasm-opt -Oz), or split this template into smaller pieces.\",\n );\n}\n"],"mappings":";;AA6BA,MAAa,sBAAsB,IAAI,OAAO;AAI9C,MAAa,kCAAkC,MAAM,OAAO,OAAO,MAAM;AAEzE,SAAS,YAAY,GAAmB;AACtC,KAAI,IAAI,KAAM,QAAO,GAAG,EAAE;AAC1B,KAAI,IAAI,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,QAAQ,EAAE,CAAC;AACrD,QAAO,IAAI,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC;;AAGzC,SAAgB,mBACd,MACA,YACA,UACM;AACN,KAAI,cAAA,QAAmC;AACvC,OAAM,IAAI,MACR,iBAAiBA,gBAAAA,iBAAiB,SAAS,CAAC,QAAQ,KAAK,MAAM,YAAY,WAAW,CAAC,0CAC3C,YAAY,oBAAoB,CAAC,oPAI9E;;;;;;;;;AAsBH,SAAgB,yBAAyB,KAA6C;CACpF,MAAM,uBAAO,IAAI,KAA+B;CAChD,SAAS,KAAK,GAAmB;AAC/B,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE;AACtD,OAAI,KAAK,IAAI,KAAK,CAAE;GACpB,MAAM,SAAS,IAAI,aAAa,IAAI;GAGpC,MAAM,cAAc,UAAU,OAAO,KAAK,MAAO,OAAO,SAAS,IAAK,EAAE,GAAG;AAC3E,QAAK,IAAI,MAAM;IAAE;IAAM;IAAa,CAAC;;AAEvC,OAAK,MAAM,OAAO,OAAO,OAAO,EAAE,aAAa,EAAE,CAAC,CAAE,MAAK,IAAI;;AAE/D,MAAK,IAAI,SAAS;AAClB,QAAO,CAAC,GAAG,KAAK,QAAQ,CAAC;;AAG3B,SAAgB,uBACd,cACA,mBACA,mBACM;AACN,KAAI,qBAAA,QAAsD;CAC1D,MAAM,SAAS,CAAC,GAAG,kBAAkB,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,YAAY;CACnF,MAAM,YACJ,OAAO,WAAW,IACd,oHACA,2DACA,OAAO,KAAK,MAAM,OAAO,EAAE,KAAK,KAAK,YAAY,EAAE,YAAY,GAAG,CAAC,KAAK,KAAK;AACnF,OAAM,IAAI,MACR,iBAAiB,aAAa,MAAM,YAAY,kBAAkB,CAAC,0CAChC,YAAY,gCAAgC,CAAC,uIAG9E,YACA,sFACH"}
@@ -9,7 +9,7 @@ function formatBytes(n) {
9
9
  }
10
10
  function assertWasmFileSize(file, byteLength, fullName) {
11
11
  if (byteLength <= 2097152) return;
12
- throw new Error(`WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)}, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). Strip debug info or run \`wasm-opt -Oz\` to shrink it.`);
12
+ throw new Error(`WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)} gzipped, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). Strip debug info or run \`wasm-opt -Oz\` to shrink it.`);
13
13
  }
14
14
  /**
15
15
  * Walks a compiled template tree and reports every WASM artefact embedded
@@ -24,10 +24,10 @@ function collectWasmContributions(tpl) {
24
24
  for (const [name, ref] of Object.entries(t.wasm ?? {})) {
25
25
  if (seen.has(name)) continue;
26
26
  const base64 = tpl.hashToSource[ref.sourceHash];
27
- const rawBytes = base64 != null ? Math.floor(base64.length * 3 / 4) : 0;
27
+ const storedBytes = base64 != null ? Math.floor(base64.length * 3 / 4) : 0;
28
28
  seen.set(name, {
29
29
  name,
30
- rawBytes
30
+ storedBytes
31
31
  });
32
32
  }
33
33
  for (const sub of Object.values(t.templates ?? {})) walk(sub);
@@ -37,8 +37,8 @@ function collectWasmContributions(tpl) {
37
37
  }
38
38
  function assertTemplatePackSize(templateName, gzippedByteLength, wasmContributions) {
39
39
  if (gzippedByteLength <= 3567616) return;
40
- const ranked = [...wasmContributions].sort((a, b) => b.rawBytes - a.rawBytes);
41
- const breakdown = ranked.length === 0 ? "\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)" : "\nWASM artefacts in this pack (raw bytes):\n" + ranked.map((w) => ` - ${w.name} — ${formatBytes(w.rawBytes)}`).join("\n");
40
+ const ranked = [...wasmContributions].sort((a, b) => b.storedBytes - a.storedBytes);
41
+ const breakdown = ranked.length === 0 ? "\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)" : "\nWASM artefacts in this pack (gzipped, pre-base64):\n" + ranked.map((w) => ` - ${w.name} — ${formatBytes(w.storedBytes)}`).join("\n");
42
42
  throw new Error(`Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. The backend caps gzipped packs at 3.5 MiB (see TemplatePackSizeLimit in pl: controllers/workflow/pkg/cfg/config.go).` + breakdown + "\nShrink WASM artefacts (wasm-opt -Oz), or split this template into smaller pieces.");
43
43
  }
44
44
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"pack_limits.js","names":[],"sources":["../../src/compiler/pack_limits.ts"],"sourcesContent":["import type { CompiledTemplateV3, TemplateDataV3 } from \"@milaboratories/pl-model-backend\";\n\nimport type { FullArtifactName } from \"./package\";\nimport { fullNameToString } from \"./package\";\n\n// Build-time size guards mirroring the two backend caps that gate template\n// ingestion. Hardcoded because tengo-builder runs at block build time and has\n// no connection to a running backend; if pl ever changes the caps, update the\n// constants here in lockstep with the source-of-truth lines pointed at below.\n//\n// Source of truth (`core/pl` repo):\n// - platform/core/transaction/assertions.go : `maxResourceDataSize`\n// 3 MiB per value resource, checked on every CreateValue marshal.\n// Hits the WasmV1 resource after the controller unpacks a template pack\n// into its constituent libs/software/wasm resources.\n// - controllers/workflow/pkg/cfg/config.go : `TemplatePackSizeLimit`\n// 3.5 MiB per gzipped template pack, checked before the pack itself is\n// stored as a TengoTemplatePackV1 value resource.\n\n// 2 MiB raw → ~2.67 MiB base64 + JSON wrapper → comfortably under the 3 MiB\n// per-value-resource cap with ~330 KiB headroom for the WasmV1Data wrapper\n// (Name, Version, Runtime, DefaultMemoryLimit, JSON syntax). WasmV1Data.Code\n// is a Go `[]byte`, which encoding/json serialises as base64 — that's where\n// the 4/3 expansion comes from.\nexport const MAX_WASM_FILE_BYTES = 2 * 1024 * 1024;\n\n// 100 KiB below the backend's 3.5 MiB so blocks don't break on small\n// platform-side metadata overhead, or if pl tightens the limit slightly.\nexport const MAX_TEMPLATE_PACK_BYTES_GZIPPED = 3.5 * 1024 * 1024 - 100 * 1024;\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`;\n return `${(n / 1024 / 1024).toFixed(2)} MiB`;\n}\n\nexport function assertWasmFileSize(\n file: string,\n byteLength: number,\n fullName: FullArtifactName,\n): void {\n if (byteLength <= MAX_WASM_FILE_BYTES) return;\n throw new Error(\n `WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)}, ` +\n `which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. ` +\n `The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON ` +\n `marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). ` +\n `Strip debug info or run \\`wasm-opt -Oz\\` to shrink it.`,\n );\n}\n\nexport interface WasmContribution {\n /** Artefact name as stored under TemplateDataV3.wasm (e.g. \"@pkg:id\"). */\n readonly name: string;\n /** Raw WASM bytes — decoded from the base64-encoded source in hashToSource. */\n readonly rawBytes: number;\n}\n\n/**\n * Walks a compiled template tree and reports every WASM artefact embedded\n * directly or transitively. Used only by the too-large-pack error message —\n * never on the success path. Deduplicates by artefact name (sub-templates can\n * import the same WASM via different aliases and we want to attribute weight\n * only once).\n */\nexport function collectWasmContributions(tpl: CompiledTemplateV3): WasmContribution[] {\n const seen = new Map<string, WasmContribution>();\n function walk(t: TemplateDataV3) {\n for (const [name, ref] of Object.entries(t.wasm ?? {})) {\n if (seen.has(name)) continue;\n const base64 = tpl.hashToSource[ref.sourceHash];\n // base64 encodes 3 raw bytes per 4 chars; the off-by-padding is at most\n // 2 bytes per artefact — fine for a human-readable size breakdown.\n const rawBytes = base64 != null ? Math.floor((base64.length * 3) / 4) : 0;\n seen.set(name, { name, rawBytes });\n }\n for (const sub of Object.values(t.templates ?? {})) walk(sub);\n }\n walk(tpl.template);\n return [...seen.values()];\n}\n\nexport function assertTemplatePackSize(\n templateName: string,\n gzippedByteLength: number,\n wasmContributions: readonly WasmContribution[],\n): void {\n if (gzippedByteLength <= MAX_TEMPLATE_PACK_BYTES_GZIPPED) return;\n const ranked = [...wasmContributions].sort((a, b) => b.rawBytes - a.rawBytes);\n const breakdown =\n ranked.length === 0\n ? \"\\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)\"\n : \"\\nWASM artefacts in this pack (raw bytes):\\n\" +\n ranked.map((w) => ` - ${w.name} — ${formatBytes(w.rawBytes)}`).join(\"\\n\");\n throw new Error(\n `Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, ` +\n `which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. ` +\n `The backend caps gzipped packs at 3.5 MiB (see TemplatePackSizeLimit in pl: ` +\n `controllers/workflow/pkg/cfg/config.go).` +\n breakdown +\n \"\\nShrink WASM artefacts (wasm-opt -Oz), or split this template into smaller pieces.\",\n );\n}\n"],"mappings":";;AAwBA,MAAa,sBAAsB,IAAI,OAAO;AAI9C,MAAa,kCAAkC,MAAM,OAAO,OAAO,MAAM;AAEzE,SAAS,YAAY,GAAmB;AACtC,KAAI,IAAI,KAAM,QAAO,GAAG,EAAE;AAC1B,KAAI,IAAI,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,QAAQ,EAAE,CAAC;AACrD,QAAO,IAAI,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC;;AAGzC,SAAgB,mBACd,MACA,YACA,UACM;AACN,KAAI,cAAA,QAAmC;AACvC,OAAM,IAAI,MACR,iBAAiB,iBAAiB,SAAS,CAAC,QAAQ,KAAK,MAAM,YAAY,WAAW,CAAC,kCACpD,YAAY,oBAAoB,CAAC,oPAIrE;;;;;;;;;AAiBH,SAAgB,yBAAyB,KAA6C;CACpF,MAAM,uBAAO,IAAI,KAA+B;CAChD,SAAS,KAAK,GAAmB;AAC/B,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE;AACtD,OAAI,KAAK,IAAI,KAAK,CAAE;GACpB,MAAM,SAAS,IAAI,aAAa,IAAI;GAGpC,MAAM,WAAW,UAAU,OAAO,KAAK,MAAO,OAAO,SAAS,IAAK,EAAE,GAAG;AACxE,QAAK,IAAI,MAAM;IAAE;IAAM;IAAU,CAAC;;AAEpC,OAAK,MAAM,OAAO,OAAO,OAAO,EAAE,aAAa,EAAE,CAAC,CAAE,MAAK,IAAI;;AAE/D,MAAK,IAAI,SAAS;AAClB,QAAO,CAAC,GAAG,KAAK,QAAQ,CAAC;;AAG3B,SAAgB,uBACd,cACA,mBACA,mBACM;AACN,KAAI,qBAAA,QAAsD;CAC1D,MAAM,SAAS,CAAC,GAAG,kBAAkB,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;CAC7E,MAAM,YACJ,OAAO,WAAW,IACd,oHACA,iDACA,OAAO,KAAK,MAAM,OAAO,EAAE,KAAK,KAAK,YAAY,EAAE,SAAS,GAAG,CAAC,KAAK,KAAK;AAChF,OAAM,IAAI,MACR,iBAAiB,aAAa,MAAM,YAAY,kBAAkB,CAAC,0CAChC,YAAY,gCAAgC,CAAC,uIAG9E,YACA,sFACH"}
1
+ {"version":3,"file":"pack_limits.js","names":[],"sources":["../../src/compiler/pack_limits.ts"],"sourcesContent":["import type { CompiledTemplateV3, TemplateDataV3 } from \"@milaboratories/pl-model-backend\";\n\nimport type { FullArtifactName } from \"./package\";\nimport { fullNameToString } from \"./package\";\n\n// Build-time size guards mirroring the two backend caps that gate template\n// ingestion. Hardcoded because tengo-builder runs at block build time and has\n// no connection to a running backend; if pl ever changes the caps, update the\n// constants here in lockstep with the source-of-truth lines pointed at below.\n//\n// Source of truth (`core/pl` repo):\n// - platform/core/transaction/assertions.go : `maxResourceDataSize`\n// 3 MiB per value resource, checked on every CreateValue marshal.\n// Hits the WasmV1 resource after the controller unpacks a template pack\n// into its constituent libs/software/wasm resources.\n// - controllers/workflow/pkg/cfg/config.go : `TemplatePackSizeLimit`\n// 3.5 MiB per gzipped template pack, checked before the pack itself is\n// stored as a TengoTemplatePackV1 value resource.\n\n// Cap on the gzipped wasm payload that ends up in WasmV1Data.Code on the\n// backend. 2 MiB gzipped → ~2.67 MiB base64 + JSON wrapper → comfortably\n// under the 3 MiB per-value-resource cap with ~330 KiB headroom for the\n// WasmV1Data wrapper (Name, Version, Runtime, DefaultMemoryLimit, JSON\n// syntax). WasmV1Data.Code is a Go `[]byte`, which encoding/json serialises\n// as base64 — that's where the 4/3 expansion comes from.\n//\n// The tengo-builder gzips wasm files before adding them to the pack; this\n// cap therefore admits raw .wasm files several times larger than 2 MiB\n// (real wasm components compress to ~30-40 % of their raw size).\nexport const MAX_WASM_FILE_BYTES = 2 * 1024 * 1024;\n\n// 100 KiB below the backend's 3.5 MiB so blocks don't break on small\n// platform-side metadata overhead, or if pl tightens the limit slightly.\nexport const MAX_TEMPLATE_PACK_BYTES_GZIPPED = 3.5 * 1024 * 1024 - 100 * 1024;\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`;\n return `${(n / 1024 / 1024).toFixed(2)} MiB`;\n}\n\nexport function assertWasmFileSize(\n file: string,\n byteLength: number,\n fullName: FullArtifactName,\n): void {\n if (byteLength <= MAX_WASM_FILE_BYTES) return;\n throw new Error(\n `WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)} ` +\n `gzipped, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. ` +\n `The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON ` +\n `marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). ` +\n `Strip debug info or run \\`wasm-opt -Oz\\` to shrink it.`,\n );\n}\n\nexport interface WasmContribution {\n /** Artefact name as stored under TemplateDataV3.wasm (e.g. \"@pkg:id\"). */\n readonly name: string;\n /**\n * Bytes this artefact contributes to the pack, measured after gzip and\n * before base64 — i.e. the size of the binary payload stored on the\n * backend in WasmV1Data.Code. Decoded from the base64-encoded source in\n * hashToSource.\n */\n readonly storedBytes: number;\n}\n\n/**\n * Walks a compiled template tree and reports every WASM artefact embedded\n * directly or transitively. Used only by the too-large-pack error message —\n * never on the success path. Deduplicates by artefact name (sub-templates can\n * import the same WASM via different aliases and we want to attribute weight\n * only once).\n */\nexport function collectWasmContributions(tpl: CompiledTemplateV3): WasmContribution[] {\n const seen = new Map<string, WasmContribution>();\n function walk(t: TemplateDataV3) {\n for (const [name, ref] of Object.entries(t.wasm ?? {})) {\n if (seen.has(name)) continue;\n const base64 = tpl.hashToSource[ref.sourceHash];\n // base64 encodes 3 binary bytes per 4 chars; the off-by-padding is at\n // most 2 bytes per artefact — fine for a human-readable size breakdown.\n const storedBytes = base64 != null ? Math.floor((base64.length * 3) / 4) : 0;\n seen.set(name, { name, storedBytes });\n }\n for (const sub of Object.values(t.templates ?? {})) walk(sub);\n }\n walk(tpl.template);\n return [...seen.values()];\n}\n\nexport function assertTemplatePackSize(\n templateName: string,\n gzippedByteLength: number,\n wasmContributions: readonly WasmContribution[],\n): void {\n if (gzippedByteLength <= MAX_TEMPLATE_PACK_BYTES_GZIPPED) return;\n const ranked = [...wasmContributions].sort((a, b) => b.storedBytes - a.storedBytes);\n const breakdown =\n ranked.length === 0\n ? \"\\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)\"\n : \"\\nWASM artefacts in this pack (gzipped, pre-base64):\\n\" +\n ranked.map((w) => ` - ${w.name} — ${formatBytes(w.storedBytes)}`).join(\"\\n\");\n throw new Error(\n `Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, ` +\n `which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. ` +\n `The backend caps gzipped packs at 3.5 MiB (see TemplatePackSizeLimit in pl: ` +\n `controllers/workflow/pkg/cfg/config.go).` +\n breakdown +\n \"\\nShrink WASM artefacts (wasm-opt -Oz), or split this template into smaller pieces.\",\n );\n}\n"],"mappings":";;AA6BA,MAAa,sBAAsB,IAAI,OAAO;AAI9C,MAAa,kCAAkC,MAAM,OAAO,OAAO,MAAM;AAEzE,SAAS,YAAY,GAAmB;AACtC,KAAI,IAAI,KAAM,QAAO,GAAG,EAAE;AAC1B,KAAI,IAAI,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,QAAQ,EAAE,CAAC;AACrD,QAAO,IAAI,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC;;AAGzC,SAAgB,mBACd,MACA,YACA,UACM;AACN,KAAI,cAAA,QAAmC;AACvC,OAAM,IAAI,MACR,iBAAiB,iBAAiB,SAAS,CAAC,QAAQ,KAAK,MAAM,YAAY,WAAW,CAAC,0CAC3C,YAAY,oBAAoB,CAAC,oPAI9E;;;;;;;;;AAsBH,SAAgB,yBAAyB,KAA6C;CACpF,MAAM,uBAAO,IAAI,KAA+B;CAChD,SAAS,KAAK,GAAmB;AAC/B,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE;AACtD,OAAI,KAAK,IAAI,KAAK,CAAE;GACpB,MAAM,SAAS,IAAI,aAAa,IAAI;GAGpC,MAAM,cAAc,UAAU,OAAO,KAAK,MAAO,OAAO,SAAS,IAAK,EAAE,GAAG;AAC3E,QAAK,IAAI,MAAM;IAAE;IAAM;IAAa,CAAC;;AAEvC,OAAK,MAAM,OAAO,OAAO,OAAO,EAAE,aAAa,EAAE,CAAC,CAAE,MAAK,IAAI;;AAE/D,MAAK,IAAI,SAAS;AAClB,QAAO,CAAC,GAAG,KAAK,QAAQ,CAAC;;AAG3B,SAAgB,uBACd,cACA,mBACA,mBACM;AACN,KAAI,qBAAA,QAAsD;CAC1D,MAAM,SAAS,CAAC,GAAG,kBAAkB,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,YAAY;CACnF,MAAM,YACJ,OAAO,WAAW,IACd,oHACA,2DACA,OAAO,KAAK,MAAM,OAAO,EAAE,KAAK,KAAK,YAAY,EAAE,YAAY,GAAG,CAAC,KAAK,KAAK;AACnF,OAAM,IAAI,MACR,iBAAiB,aAAa,MAAM,YAAY,kBAAkB,CAAC,0CAChC,YAAY,gCAAgC,CAAC,uIAG9E,YACA,sFACH"}
@@ -6,7 +6,7 @@ let node_crypto = require("node:crypto");
6
6
  //#region src/compiler/source.ts
7
7
  const namePattern = "[_a-zA-Z][_a-zA-Z0-9]*";
8
8
  const functionCallRE = (moduleName, fnName) => {
9
- return new RegExp(`\\b${moduleName}\\.(?<fnCall>(?<fnName>` + fnName + `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*\\))`, "g");
9
+ return new RegExp(`\\b${moduleName}\\.(?<fnCall>(?<fnName>` + fnName + `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*)(?=[,)])`, "g");
10
10
  };
11
11
  const functionCallLikeRE = (moduleName, fnName) => {
12
12
  return new RegExp(`\\b${moduleName}\\.(?<fnName>` + fnName + `)\\s*\\(`, "g");
@@ -234,7 +234,7 @@ function processAssetImport(originalLine, statement, context, localPackageName,
234
234
  const artifact = parseArtifactName(templateName, artifactType, localPackageName);
235
235
  if (!artifact) throw Error(`failed to parse artifact name in ${fnName} import statement`);
236
236
  artifacts.push(artifact);
237
- if (globalizeImports) originalLine = originalLine.replaceAll(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}")`);
237
+ if (globalizeImports) originalLine = originalLine.replaceAll(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}"`);
238
238
  }
239
239
  return {
240
240
  line: originalLine,
@@ -1 +1 @@
1
- {"version":3,"file":"source.cjs","names":["createArtifactNameSet","fullNameToString"],"sources":["../../src/compiler/source.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport {\n type TypedArtifactName,\n type FullArtifactName,\n type ArtifactType,\n type CompileMode,\n type CompilerOption,\n fullNameToString,\n} from \"./package\";\nimport type { ArtifactMap } from \"./artifactset\";\nimport { createArtifactNameSet } from \"./artifactset\";\nimport { createHash } from \"node:crypto\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\n\n// matches any valid name in tengo. Don't forget to use '\\b' when needed to limit the boundaries!\nconst namePattern = \"[_a-zA-Z][_a-zA-Z0-9]*\";\n\nconst functionCallRE = (moduleName: string, fnName: string) => {\n return new RegExp(\n `\\\\b${moduleName}\\\\.(?<fnCall>(?<fnName>` +\n fnName +\n `)\\\\s*\\\\(\\\\s*\"(?<templateName>[^\"]+)\"\\\\s*\\\\))`,\n \"g\",\n );\n};\n\nconst functionCallLikeRE = (moduleName: string, fnName: string) => {\n return new RegExp(`\\\\b${moduleName}\\\\.(?<fnName>` + fnName + `)\\\\s*\\\\(`, \"g\");\n};\n\nexport const newGetTemplateIdRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getTemplateId\");\nexport const newGetSoftwareInfoRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getSoftwareInfo\");\n\nconst newImportTemplateRE = (moduleName: string) => functionCallRE(moduleName, \"importTemplate\");\nconst newImportTemplateDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importTemplate\");\nconst newImportSoftwareRE = (moduleName: string) => functionCallRE(moduleName, \"importSoftware\");\nconst newImportSoftwareDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importSoftware\");\nconst newImportAssetRE = (moduleName: string) => functionCallRE(moduleName, \"importAsset\");\nconst newImportAssetDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importAsset\");\nconst newImportWasmRE = (moduleName: string) => functionCallRE(moduleName, \"importWasm\");\nconst newImportWasmDetector = (moduleName: string) => functionCallLikeRE(moduleName, \"importWasm\");\n\nconst emptyLineRE = /^\\s*$/;\nconst compilerOptionRE = /^\\/\\/tengo:[\\w]/;\nconst wrongCompilerOptionRE = /^\\s*\\/\\/\\s*tengo:\\s*./;\nconst singlelineCommentRE = /^\\s*(\\/\\/)/;\nconst singlelineTerminatedCommentRE = /^\\s*\\/\\*.*\\*\\/\\s*$/; // matches '^/* ... */$' comment lines as a special case of singleline comments.\nconst multilineCommentStartRE = /^\\s*\\/\\*/;\nconst multilineCommentEndRE = /\\*\\//;\nconst multilineStatementRE = /[.,]\\s*$/; // it is hard to consistently treat (\\n\"a\"\\n) multiline statements, we forbid them for now.\n\n// import could only be an assignment in a statement,\n// other ways could break a compilation.\nconst importRE = /\\s*:=\\s*import\\s*\\(\\s*\"(?<moduleName>[^\"]+)\"\\s*\\)/;\nconst importNameRE = new RegExp(\n `\\\\b(?<importName>${namePattern}(\\\\.${namePattern})*)${importRE.source}`,\n);\nconst dependencyRE = /(?<pkgName>[^\"]+)?:(?<depID>[^\"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID\n\n/**\n * Parse compiler option string representation\n * Compiler option line is a comment starting with '//tengo:', say\n * //tengo:hash_override tralala\n *\n * The common compiler option syntax is:\n * //tengo:<option name> [<option arg1> [<option arg 2> [...]]]\n */\nconst parseComplierOption = (opt: string): CompilerOption => {\n const parts = opt.split(\" \");\n const namePart = parts[0].split(\":\");\n if (namePart.length != 2) {\n throw new Error(\n \"compiler option format is wrong: expect to have option name after 'tengo:' prefix, like 'tengo:MyOption'\",\n );\n }\n const optName = namePart[1];\n\n return {\n name: optName,\n args: parts.slice(1),\n };\n};\n\nexport class ArtifactSource {\n constructor(\n /** The mode this artifact was built (dev or dist) */\n public readonly compileMode: CompileMode,\n /** Full artifact id, including package version */\n public readonly fullName: FullArtifactName,\n /** Hash of the source code */\n public readonly sourceHash: string,\n /** Normalized source code */\n public readonly src: string,\n /** Path to source file where artifact came from */\n public readonly srcName: string,\n /** List of dependencies */\n public readonly dependencies: TypedArtifactName[],\n /** Additional compiler options detected in source code */\n public readonly compilerOptions: CompilerOption[],\n ) {}\n}\n\nexport function parseSourceFile(\n logger: MiLogger,\n mode: CompileMode,\n srcFile: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const src = readFileSync(srcFile).toString();\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n srcFile,\n deps.array,\n opts,\n );\n}\n\nexport function parseSource(\n logger: MiLogger,\n mode: CompileMode,\n src: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n \"\",\n deps.array,\n opts,\n );\n}\n\n/**\n * Reads src\n * returns normalized source code,\n * gets dependencies from imports,\n * maps imports to global names if globalizeImports is true,\n * and collects compiler options like hashOverride.\n */\nfunction parseSourceData(\n logger: MiLogger,\n src: string,\n fullSourceName: FullArtifactName,\n globalizeImports: boolean,\n): {\n normalized: string;\n deps: ArtifactMap<TypedArtifactName>;\n opts: CompilerOption[];\n} {\n const dependencySet = createArtifactNameSet();\n const optionList: CompilerOption[] = [];\n\n // iterating over lines\n const lines = src.split(\"\\n\");\n\n // processedLines keep all the original lines from <src>.\n // If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines\n // with Platforma Tengo lib and template usages, resolving local names (\":<item>\") to\n // global (\"@milaboratory/pkg:<item>\")\n const processedLines: string[] = [];\n let parserContext: sourceParserContext = {\n isInCommentBlock: false,\n canDetectOptions: true,\n artifactImportREs: new Map<string, [ArtifactType, RegExp][]>(),\n importLikeREs: new Map<string, [ArtifactType, RegExp][]>(),\n multilineStatement: \"\",\n lineNo: 0,\n };\n\n for (const line of lines) {\n parserContext.lineNo++;\n\n try {\n const {\n line: processedLine,\n context: newContext,\n artifacts,\n option,\n } = parseSingleSourceLine(logger, line, parserContext, fullSourceName.pkg, globalizeImports);\n processedLines.push(processedLine);\n parserContext = newContext;\n\n for (const artifact of artifacts ?? []) {\n dependencySet.add(artifact);\n }\n if (option) {\n optionList.push(option);\n }\n } catch (error: unknown) {\n const err = error as Error;\n throw new Error(\n `[line ${parserContext.lineNo} in ${fullNameToString(fullSourceName)}]: ${err.message}\\n\\t${line}`,\n { cause: err },\n );\n }\n }\n\n return {\n normalized: processedLines.join(\"\\n\"),\n deps: dependencySet,\n opts: optionList,\n };\n}\n\nexport type sourceParserContext = {\n isInCommentBlock: boolean;\n canDetectOptions: boolean;\n artifactImportREs: Map<string, [ArtifactType, RegExp][]>;\n importLikeREs: Map<string, [ArtifactType, RegExp][]>;\n multilineStatement: string;\n lineNo: number;\n};\n\nexport type lineProcessingResult = {\n line: string;\n context: sourceParserContext;\n artifacts: TypedArtifactName[];\n option: CompilerOption | undefined;\n};\n\nexport function parseSingleSourceLine(\n logger: MiLogger,\n line: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (context.isInCommentBlock) {\n if (multilineCommentEndRE.exec(line)) {\n context.isInCommentBlock = false;\n }\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n if (compilerOptionRE.exec(line)) {\n if (!context.canDetectOptions) {\n logger.error(\n `[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`,\n );\n throw new Error(\n \"tengo compiler options ('//tengo:' comments) can be set only in file header\",\n );\n }\n return { line, context, artifacts: [], option: parseComplierOption(line) };\n }\n\n if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {\n logger.warn(\n `[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`,\n );\n return { line, context, artifacts: [], option: undefined };\n }\n\n if (singlelineCommentRE.test(line) || singlelineTerminatedCommentRE.test(line)) {\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const canBeInlinedComment = line.includes(\"*/\");\n if (multilineCommentStartRE.exec(line) && !canBeInlinedComment) {\n context.isInCommentBlock = true;\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const statement = context.multilineStatement + line.trim();\n\n const mayContainAComment = line.includes(\"//\") || line.includes(\"/*\");\n if (multilineStatementRE.test(line) && !mayContainAComment) {\n // We accumulate multiline statements into single line before analyzing them.\n // This dramatically simplifies parsing logic: things like\n //\n // assets.\n // importSoftware(\"a:b\");\n //\n // become simple 'assets.importSoftware(\"a:b\");' for parser checks.\n //\n // For safety reasons, we never consider anything that 'may look like a comment'\n // as a part of multiline statement to prevent joining things like\n //\n // someFnCall() // looks like multiline statement because of dot in the end of a comment.\n //\n // This problem also appears in multiline string literals, but I hope this will not\n // cause problems in real life.\n\n // We still try to process each line to globalize imports in case of complex constructions, when\n // statements are stacked one into another:\n // a.\n // use(assets.importSoftware(\":soft1\")).\n // use(assets.importSoftware(\":soft2\")).\n // run()\n // It is multiline, and it still requires import globalization mid-way, not just for the last line of statement\n const result = processAssetImport(line, statement, context, localPackageName, globalizeImports);\n context.multilineStatement += result.line.trim(); // accumulate the line after imports globalization.\n return result;\n }\n\n context.multilineStatement = \"\"; // reset accumulated multiline statement parts once we reach statement end.\n\n if (emptyLineRE.exec(statement)) {\n return { line, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n return processAssetImport(line, statement, context, localPackageName, globalizeImports);\n}\n\nfunction processModuleImport(\n importInstruction: RegExpExecArray,\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n const iInfo = parseImport(statement);\n\n // If we have plapi, ll or assets, then try to parse\n // getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.\n\n if (iInfo.module === \"plapi\") {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newGetTemplateIdRE(iInfo.alias)],\n [\"software\", newGetSoftwareInfoRE(iInfo.alias)],\n ]);\n }\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:ll\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:ll\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":ll\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n ]);\n }\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:assets\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:assets\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":assets\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n [\"asset\", newImportAssetRE(iInfo.alias)],\n [\"wasm\", newImportWasmRE(iInfo.alias)],\n ]);\n context.importLikeREs.set(iInfo.module, [\n [\"template\", newImportTemplateDetector(iInfo.alias)],\n [\"software\", newImportSoftwareDetector(iInfo.alias)],\n [\"asset\", newImportAssetDetector(iInfo.alias)],\n [\"wasm\", newImportWasmDetector(iInfo.alias)],\n ]);\n }\n }\n\n const artifact = parseArtifactName(iInfo.module, \"library\", localPackageName);\n if (!artifact) {\n // not a Platforma Tengo library import\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (globalizeImports) {\n originalLine = originalLine.replace(\n importInstruction[0],\n ` := import(\"${artifact.pkg}:${artifact.id}\")`,\n );\n }\n\n return { line: originalLine, context, artifacts: [artifact], option: undefined };\n}\n\nfunction processAssetImport(\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (emptyLineRE.exec(statement)) {\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n const importInstruction = importRE.exec(statement);\n\n if (importInstruction) {\n return processModuleImport(\n importInstruction,\n originalLine,\n statement,\n context,\n localPackageName,\n globalizeImports,\n );\n }\n\n if (context.artifactImportREs.size > 0) {\n for (const [_, artifactRE] of context.artifactImportREs) {\n for (const [artifactType, re] of artifactRE) {\n // Find all matches in the statement\n const matches = Array.from(statement.matchAll(re));\n if (matches.length === 0) {\n continue;\n }\n\n const artifacts: TypedArtifactName[] = [];\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n if (!match || !match.groups) {\n continue;\n }\n\n const { fnCall, templateName, fnName } = match.groups;\n\n if (!fnCall || !templateName || !fnName) {\n throw Error(`failed to parse template import statement`);\n }\n\n const artifact = parseArtifactName(templateName, artifactType, localPackageName);\n if (!artifact) {\n throw Error(`failed to parse artifact name in ${fnName} import statement`);\n }\n artifacts.push(artifact);\n\n if (globalizeImports) {\n // Replace all occurrences of this fnCall in originalLine\n originalLine = originalLine.replaceAll(\n fnCall,\n `${fnName}(\"${artifact.pkg}:${artifact.id}\")`,\n );\n }\n }\n\n return { line: originalLine, context, artifacts, option: undefined };\n }\n }\n }\n\n if (context.importLikeREs.size > 0) {\n for (const [_, artifactRE] of context.importLikeREs) {\n for (const [artifactType, re] of artifactRE) {\n const match = re.exec(statement);\n if (!match || !match.groups) {\n continue;\n }\n\n throw Error(\n `incorrect '${artifactType}' import statement: use string literal as ID (variables are not allowed) in the same line with brackets (i.e. 'importSoftware(\"sw:main\")').`,\n );\n }\n }\n }\n\n return { line: originalLine, context, artifacts: [], option: undefined };\n}\n\ninterface ImportInfo {\n module: string; // the module name without wrapping quotes: import(\"<module>\")\n alias: string; // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n}\n\nfunction parseImport(line: string): ImportInfo {\n const match = importNameRE.exec(line);\n\n if (!match || !match.groups) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n const { importName, moduleName } = match.groups;\n if (!importName || !moduleName) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n return {\n module: moduleName, // the module name without wrapping quotes: import(\"<module>\")\n alias: importName, // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n };\n}\n\nfunction parseArtifactName(\n moduleName: string,\n aType: ArtifactType,\n localPackageName: string,\n): TypedArtifactName | undefined {\n const depInfo = dependencyRE.exec(moduleName);\n if (!depInfo) {\n return;\n }\n\n if (!depInfo.groups) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n const { pkgName, depID } = depInfo.groups;\n if (!depID) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n return { type: aType, pkg: pkgName ?? localPackageName, id: depID };\n}\n\nexport function getSha256(source: string): string {\n return createHash(\"sha256\").update(source).digest(\"hex\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"source.cjs","names":["createArtifactNameSet","fullNameToString"],"sources":["../../src/compiler/source.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport {\n type TypedArtifactName,\n type FullArtifactName,\n type ArtifactType,\n type CompileMode,\n type CompilerOption,\n fullNameToString,\n} from \"./package\";\nimport type { ArtifactMap } from \"./artifactset\";\nimport { createArtifactNameSet } from \"./artifactset\";\nimport { createHash } from \"node:crypto\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\n\n// matches any valid name in tengo. Don't forget to use '\\b' when needed to limit the boundaries!\nconst namePattern = \"[_a-zA-Z][_a-zA-Z0-9]*\";\n\nconst functionCallRE = (moduleName: string, fnName: string) => {\n // `fnCall` captures from the function name through the first string\n // argument (including the closing quote and any trailing whitespace);\n // the closing-paren-or-comma check is a non-consuming lookahead, so\n // any extra args (`assets.importWasm(\"name\", { memoryLimit: ... })`)\n // survive the rewrite in `compiler.ts` — only the literal is\n // build-time material, anything past it is runtime config.\n return new RegExp(\n `\\\\b${moduleName}\\\\.(?<fnCall>(?<fnName>` +\n fnName +\n `)\\\\s*\\\\(\\\\s*\"(?<templateName>[^\"]+)\"\\\\s*)(?=[,)])`,\n \"g\",\n );\n};\n\nconst functionCallLikeRE = (moduleName: string, fnName: string) => {\n return new RegExp(`\\\\b${moduleName}\\\\.(?<fnName>` + fnName + `)\\\\s*\\\\(`, \"g\");\n};\n\nexport const newGetTemplateIdRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getTemplateId\");\nexport const newGetSoftwareInfoRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getSoftwareInfo\");\n\nconst newImportTemplateRE = (moduleName: string) => functionCallRE(moduleName, \"importTemplate\");\nconst newImportTemplateDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importTemplate\");\nconst newImportSoftwareRE = (moduleName: string) => functionCallRE(moduleName, \"importSoftware\");\nconst newImportSoftwareDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importSoftware\");\nconst newImportAssetRE = (moduleName: string) => functionCallRE(moduleName, \"importAsset\");\nconst newImportAssetDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importAsset\");\nconst newImportWasmRE = (moduleName: string) => functionCallRE(moduleName, \"importWasm\");\nconst newImportWasmDetector = (moduleName: string) => functionCallLikeRE(moduleName, \"importWasm\");\n\nconst emptyLineRE = /^\\s*$/;\nconst compilerOptionRE = /^\\/\\/tengo:[\\w]/;\nconst wrongCompilerOptionRE = /^\\s*\\/\\/\\s*tengo:\\s*./;\nconst singlelineCommentRE = /^\\s*(\\/\\/)/;\nconst singlelineTerminatedCommentRE = /^\\s*\\/\\*.*\\*\\/\\s*$/; // matches '^/* ... */$' comment lines as a special case of singleline comments.\nconst multilineCommentStartRE = /^\\s*\\/\\*/;\nconst multilineCommentEndRE = /\\*\\//;\nconst multilineStatementRE = /[.,]\\s*$/; // it is hard to consistently treat (\\n\"a\"\\n) multiline statements, we forbid them for now.\n\n// import could only be an assignment in a statement,\n// other ways could break a compilation.\nconst importRE = /\\s*:=\\s*import\\s*\\(\\s*\"(?<moduleName>[^\"]+)\"\\s*\\)/;\nconst importNameRE = new RegExp(\n `\\\\b(?<importName>${namePattern}(\\\\.${namePattern})*)${importRE.source}`,\n);\nconst dependencyRE = /(?<pkgName>[^\"]+)?:(?<depID>[^\"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID\n\n/**\n * Parse compiler option string representation\n * Compiler option line is a comment starting with '//tengo:', say\n * //tengo:hash_override tralala\n *\n * The common compiler option syntax is:\n * //tengo:<option name> [<option arg1> [<option arg 2> [...]]]\n */\nconst parseComplierOption = (opt: string): CompilerOption => {\n const parts = opt.split(\" \");\n const namePart = parts[0].split(\":\");\n if (namePart.length != 2) {\n throw new Error(\n \"compiler option format is wrong: expect to have option name after 'tengo:' prefix, like 'tengo:MyOption'\",\n );\n }\n const optName = namePart[1];\n\n return {\n name: optName,\n args: parts.slice(1),\n };\n};\n\nexport class ArtifactSource {\n constructor(\n /** The mode this artifact was built (dev or dist) */\n public readonly compileMode: CompileMode,\n /** Full artifact id, including package version */\n public readonly fullName: FullArtifactName,\n /** Hash of the source code */\n public readonly sourceHash: string,\n /** Normalized source code */\n public readonly src: string,\n /** Path to source file where artifact came from */\n public readonly srcName: string,\n /** List of dependencies */\n public readonly dependencies: TypedArtifactName[],\n /** Additional compiler options detected in source code */\n public readonly compilerOptions: CompilerOption[],\n ) {}\n}\n\nexport function parseSourceFile(\n logger: MiLogger,\n mode: CompileMode,\n srcFile: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const src = readFileSync(srcFile).toString();\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n srcFile,\n deps.array,\n opts,\n );\n}\n\nexport function parseSource(\n logger: MiLogger,\n mode: CompileMode,\n src: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n \"\",\n deps.array,\n opts,\n );\n}\n\n/**\n * Reads src\n * returns normalized source code,\n * gets dependencies from imports,\n * maps imports to global names if globalizeImports is true,\n * and collects compiler options like hashOverride.\n */\nfunction parseSourceData(\n logger: MiLogger,\n src: string,\n fullSourceName: FullArtifactName,\n globalizeImports: boolean,\n): {\n normalized: string;\n deps: ArtifactMap<TypedArtifactName>;\n opts: CompilerOption[];\n} {\n const dependencySet = createArtifactNameSet();\n const optionList: CompilerOption[] = [];\n\n // iterating over lines\n const lines = src.split(\"\\n\");\n\n // processedLines keep all the original lines from <src>.\n // If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines\n // with Platforma Tengo lib and template usages, resolving local names (\":<item>\") to\n // global (\"@milaboratory/pkg:<item>\")\n const processedLines: string[] = [];\n let parserContext: sourceParserContext = {\n isInCommentBlock: false,\n canDetectOptions: true,\n artifactImportREs: new Map<string, [ArtifactType, RegExp][]>(),\n importLikeREs: new Map<string, [ArtifactType, RegExp][]>(),\n multilineStatement: \"\",\n lineNo: 0,\n };\n\n for (const line of lines) {\n parserContext.lineNo++;\n\n try {\n const {\n line: processedLine,\n context: newContext,\n artifacts,\n option,\n } = parseSingleSourceLine(logger, line, parserContext, fullSourceName.pkg, globalizeImports);\n processedLines.push(processedLine);\n parserContext = newContext;\n\n for (const artifact of artifacts ?? []) {\n dependencySet.add(artifact);\n }\n if (option) {\n optionList.push(option);\n }\n } catch (error: unknown) {\n const err = error as Error;\n throw new Error(\n `[line ${parserContext.lineNo} in ${fullNameToString(fullSourceName)}]: ${err.message}\\n\\t${line}`,\n { cause: err },\n );\n }\n }\n\n return {\n normalized: processedLines.join(\"\\n\"),\n deps: dependencySet,\n opts: optionList,\n };\n}\n\nexport type sourceParserContext = {\n isInCommentBlock: boolean;\n canDetectOptions: boolean;\n artifactImportREs: Map<string, [ArtifactType, RegExp][]>;\n importLikeREs: Map<string, [ArtifactType, RegExp][]>;\n multilineStatement: string;\n lineNo: number;\n};\n\nexport type lineProcessingResult = {\n line: string;\n context: sourceParserContext;\n artifacts: TypedArtifactName[];\n option: CompilerOption | undefined;\n};\n\nexport function parseSingleSourceLine(\n logger: MiLogger,\n line: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (context.isInCommentBlock) {\n if (multilineCommentEndRE.exec(line)) {\n context.isInCommentBlock = false;\n }\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n if (compilerOptionRE.exec(line)) {\n if (!context.canDetectOptions) {\n logger.error(\n `[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`,\n );\n throw new Error(\n \"tengo compiler options ('//tengo:' comments) can be set only in file header\",\n );\n }\n return { line, context, artifacts: [], option: parseComplierOption(line) };\n }\n\n if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {\n logger.warn(\n `[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`,\n );\n return { line, context, artifacts: [], option: undefined };\n }\n\n if (singlelineCommentRE.test(line) || singlelineTerminatedCommentRE.test(line)) {\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const canBeInlinedComment = line.includes(\"*/\");\n if (multilineCommentStartRE.exec(line) && !canBeInlinedComment) {\n context.isInCommentBlock = true;\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const statement = context.multilineStatement + line.trim();\n\n const mayContainAComment = line.includes(\"//\") || line.includes(\"/*\");\n if (multilineStatementRE.test(line) && !mayContainAComment) {\n // We accumulate multiline statements into single line before analyzing them.\n // This dramatically simplifies parsing logic: things like\n //\n // assets.\n // importSoftware(\"a:b\");\n //\n // become simple 'assets.importSoftware(\"a:b\");' for parser checks.\n //\n // For safety reasons, we never consider anything that 'may look like a comment'\n // as a part of multiline statement to prevent joining things like\n //\n // someFnCall() // looks like multiline statement because of dot in the end of a comment.\n //\n // This problem also appears in multiline string literals, but I hope this will not\n // cause problems in real life.\n\n // We still try to process each line to globalize imports in case of complex constructions, when\n // statements are stacked one into another:\n // a.\n // use(assets.importSoftware(\":soft1\")).\n // use(assets.importSoftware(\":soft2\")).\n // run()\n // It is multiline, and it still requires import globalization mid-way, not just for the last line of statement\n const result = processAssetImport(line, statement, context, localPackageName, globalizeImports);\n context.multilineStatement += result.line.trim(); // accumulate the line after imports globalization.\n return result;\n }\n\n context.multilineStatement = \"\"; // reset accumulated multiline statement parts once we reach statement end.\n\n if (emptyLineRE.exec(statement)) {\n return { line, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n return processAssetImport(line, statement, context, localPackageName, globalizeImports);\n}\n\nfunction processModuleImport(\n importInstruction: RegExpExecArray,\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n const iInfo = parseImport(statement);\n\n // If we have plapi, ll or assets, then try to parse\n // getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.\n\n if (iInfo.module === \"plapi\") {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newGetTemplateIdRE(iInfo.alias)],\n [\"software\", newGetSoftwareInfoRE(iInfo.alias)],\n ]);\n }\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:ll\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:ll\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":ll\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n ]);\n }\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:assets\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:assets\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":assets\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n [\"asset\", newImportAssetRE(iInfo.alias)],\n [\"wasm\", newImportWasmRE(iInfo.alias)],\n ]);\n context.importLikeREs.set(iInfo.module, [\n [\"template\", newImportTemplateDetector(iInfo.alias)],\n [\"software\", newImportSoftwareDetector(iInfo.alias)],\n [\"asset\", newImportAssetDetector(iInfo.alias)],\n [\"wasm\", newImportWasmDetector(iInfo.alias)],\n ]);\n }\n }\n\n const artifact = parseArtifactName(iInfo.module, \"library\", localPackageName);\n if (!artifact) {\n // not a Platforma Tengo library import\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (globalizeImports) {\n originalLine = originalLine.replace(\n importInstruction[0],\n ` := import(\"${artifact.pkg}:${artifact.id}\")`,\n );\n }\n\n return { line: originalLine, context, artifacts: [artifact], option: undefined };\n}\n\nfunction processAssetImport(\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (emptyLineRE.exec(statement)) {\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n const importInstruction = importRE.exec(statement);\n\n if (importInstruction) {\n return processModuleImport(\n importInstruction,\n originalLine,\n statement,\n context,\n localPackageName,\n globalizeImports,\n );\n }\n\n if (context.artifactImportREs.size > 0) {\n for (const [_, artifactRE] of context.artifactImportREs) {\n for (const [artifactType, re] of artifactRE) {\n // Find all matches in the statement\n const matches = Array.from(statement.matchAll(re));\n if (matches.length === 0) {\n continue;\n }\n\n const artifacts: TypedArtifactName[] = [];\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n if (!match || !match.groups) {\n continue;\n }\n\n const { fnCall, templateName, fnName } = match.groups;\n\n if (!fnCall || !templateName || !fnName) {\n throw Error(`failed to parse template import statement`);\n }\n\n const artifact = parseArtifactName(templateName, artifactType, localPackageName);\n if (!artifact) {\n throw Error(`failed to parse artifact name in ${fnName} import statement`);\n }\n artifacts.push(artifact);\n\n if (globalizeImports) {\n // Replace all occurrences of this fnCall in originalLine.\n // fnCall ends right after the literal's closing quote + ws;\n // the trailing `)` or `,` is preserved from the original\n // line, so multi-arg calls (`fn(\"name\", opts)`) keep their\n // remaining args intact.\n originalLine = originalLine.replaceAll(\n fnCall,\n `${fnName}(\"${artifact.pkg}:${artifact.id}\"`,\n );\n }\n }\n\n return { line: originalLine, context, artifacts, option: undefined };\n }\n }\n }\n\n if (context.importLikeREs.size > 0) {\n for (const [_, artifactRE] of context.importLikeREs) {\n for (const [artifactType, re] of artifactRE) {\n const match = re.exec(statement);\n if (!match || !match.groups) {\n continue;\n }\n\n throw Error(\n `incorrect '${artifactType}' import statement: use string literal as ID (variables are not allowed) in the same line with brackets (i.e. 'importSoftware(\"sw:main\")').`,\n );\n }\n }\n }\n\n return { line: originalLine, context, artifacts: [], option: undefined };\n}\n\ninterface ImportInfo {\n module: string; // the module name without wrapping quotes: import(\"<module>\")\n alias: string; // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n}\n\nfunction parseImport(line: string): ImportInfo {\n const match = importNameRE.exec(line);\n\n if (!match || !match.groups) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n const { importName, moduleName } = match.groups;\n if (!importName || !moduleName) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n return {\n module: moduleName, // the module name without wrapping quotes: import(\"<module>\")\n alias: importName, // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n };\n}\n\nfunction parseArtifactName(\n moduleName: string,\n aType: ArtifactType,\n localPackageName: string,\n): TypedArtifactName | undefined {\n const depInfo = dependencyRE.exec(moduleName);\n if (!depInfo) {\n return;\n }\n\n if (!depInfo.groups) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n const { pkgName, depID } = depInfo.groups;\n if (!depID) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n return { type: aType, pkg: pkgName ?? localPackageName, id: depID };\n}\n\nexport function getSha256(source: string): string {\n return createHash(\"sha256\").update(source).digest(\"hex\");\n}\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { createHash } from "node:crypto";
5
5
  //#region src/compiler/source.ts
6
6
  const namePattern = "[_a-zA-Z][_a-zA-Z0-9]*";
7
7
  const functionCallRE = (moduleName, fnName) => {
8
- return new RegExp(`\\b${moduleName}\\.(?<fnCall>(?<fnName>` + fnName + `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*\\))`, "g");
8
+ return new RegExp(`\\b${moduleName}\\.(?<fnCall>(?<fnName>` + fnName + `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*)(?=[,)])`, "g");
9
9
  };
10
10
  const functionCallLikeRE = (moduleName, fnName) => {
11
11
  return new RegExp(`\\b${moduleName}\\.(?<fnName>` + fnName + `)\\s*\\(`, "g");
@@ -233,7 +233,7 @@ function processAssetImport(originalLine, statement, context, localPackageName,
233
233
  const artifact = parseArtifactName(templateName, artifactType, localPackageName);
234
234
  if (!artifact) throw Error(`failed to parse artifact name in ${fnName} import statement`);
235
235
  artifacts.push(artifact);
236
- if (globalizeImports) originalLine = originalLine.replaceAll(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}")`);
236
+ if (globalizeImports) originalLine = originalLine.replaceAll(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}"`);
237
237
  }
238
238
  return {
239
239
  line: originalLine,
@@ -1 +1 @@
1
- {"version":3,"file":"source.js","names":[],"sources":["../../src/compiler/source.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport {\n type TypedArtifactName,\n type FullArtifactName,\n type ArtifactType,\n type CompileMode,\n type CompilerOption,\n fullNameToString,\n} from \"./package\";\nimport type { ArtifactMap } from \"./artifactset\";\nimport { createArtifactNameSet } from \"./artifactset\";\nimport { createHash } from \"node:crypto\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\n\n// matches any valid name in tengo. Don't forget to use '\\b' when needed to limit the boundaries!\nconst namePattern = \"[_a-zA-Z][_a-zA-Z0-9]*\";\n\nconst functionCallRE = (moduleName: string, fnName: string) => {\n return new RegExp(\n `\\\\b${moduleName}\\\\.(?<fnCall>(?<fnName>` +\n fnName +\n `)\\\\s*\\\\(\\\\s*\"(?<templateName>[^\"]+)\"\\\\s*\\\\))`,\n \"g\",\n );\n};\n\nconst functionCallLikeRE = (moduleName: string, fnName: string) => {\n return new RegExp(`\\\\b${moduleName}\\\\.(?<fnName>` + fnName + `)\\\\s*\\\\(`, \"g\");\n};\n\nexport const newGetTemplateIdRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getTemplateId\");\nexport const newGetSoftwareInfoRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getSoftwareInfo\");\n\nconst newImportTemplateRE = (moduleName: string) => functionCallRE(moduleName, \"importTemplate\");\nconst newImportTemplateDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importTemplate\");\nconst newImportSoftwareRE = (moduleName: string) => functionCallRE(moduleName, \"importSoftware\");\nconst newImportSoftwareDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importSoftware\");\nconst newImportAssetRE = (moduleName: string) => functionCallRE(moduleName, \"importAsset\");\nconst newImportAssetDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importAsset\");\nconst newImportWasmRE = (moduleName: string) => functionCallRE(moduleName, \"importWasm\");\nconst newImportWasmDetector = (moduleName: string) => functionCallLikeRE(moduleName, \"importWasm\");\n\nconst emptyLineRE = /^\\s*$/;\nconst compilerOptionRE = /^\\/\\/tengo:[\\w]/;\nconst wrongCompilerOptionRE = /^\\s*\\/\\/\\s*tengo:\\s*./;\nconst singlelineCommentRE = /^\\s*(\\/\\/)/;\nconst singlelineTerminatedCommentRE = /^\\s*\\/\\*.*\\*\\/\\s*$/; // matches '^/* ... */$' comment lines as a special case of singleline comments.\nconst multilineCommentStartRE = /^\\s*\\/\\*/;\nconst multilineCommentEndRE = /\\*\\//;\nconst multilineStatementRE = /[.,]\\s*$/; // it is hard to consistently treat (\\n\"a\"\\n) multiline statements, we forbid them for now.\n\n// import could only be an assignment in a statement,\n// other ways could break a compilation.\nconst importRE = /\\s*:=\\s*import\\s*\\(\\s*\"(?<moduleName>[^\"]+)\"\\s*\\)/;\nconst importNameRE = new RegExp(\n `\\\\b(?<importName>${namePattern}(\\\\.${namePattern})*)${importRE.source}`,\n);\nconst dependencyRE = /(?<pkgName>[^\"]+)?:(?<depID>[^\"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID\n\n/**\n * Parse compiler option string representation\n * Compiler option line is a comment starting with '//tengo:', say\n * //tengo:hash_override tralala\n *\n * The common compiler option syntax is:\n * //tengo:<option name> [<option arg1> [<option arg 2> [...]]]\n */\nconst parseComplierOption = (opt: string): CompilerOption => {\n const parts = opt.split(\" \");\n const namePart = parts[0].split(\":\");\n if (namePart.length != 2) {\n throw new Error(\n \"compiler option format is wrong: expect to have option name after 'tengo:' prefix, like 'tengo:MyOption'\",\n );\n }\n const optName = namePart[1];\n\n return {\n name: optName,\n args: parts.slice(1),\n };\n};\n\nexport class ArtifactSource {\n constructor(\n /** The mode this artifact was built (dev or dist) */\n public readonly compileMode: CompileMode,\n /** Full artifact id, including package version */\n public readonly fullName: FullArtifactName,\n /** Hash of the source code */\n public readonly sourceHash: string,\n /** Normalized source code */\n public readonly src: string,\n /** Path to source file where artifact came from */\n public readonly srcName: string,\n /** List of dependencies */\n public readonly dependencies: TypedArtifactName[],\n /** Additional compiler options detected in source code */\n public readonly compilerOptions: CompilerOption[],\n ) {}\n}\n\nexport function parseSourceFile(\n logger: MiLogger,\n mode: CompileMode,\n srcFile: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const src = readFileSync(srcFile).toString();\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n srcFile,\n deps.array,\n opts,\n );\n}\n\nexport function parseSource(\n logger: MiLogger,\n mode: CompileMode,\n src: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n \"\",\n deps.array,\n opts,\n );\n}\n\n/**\n * Reads src\n * returns normalized source code,\n * gets dependencies from imports,\n * maps imports to global names if globalizeImports is true,\n * and collects compiler options like hashOverride.\n */\nfunction parseSourceData(\n logger: MiLogger,\n src: string,\n fullSourceName: FullArtifactName,\n globalizeImports: boolean,\n): {\n normalized: string;\n deps: ArtifactMap<TypedArtifactName>;\n opts: CompilerOption[];\n} {\n const dependencySet = createArtifactNameSet();\n const optionList: CompilerOption[] = [];\n\n // iterating over lines\n const lines = src.split(\"\\n\");\n\n // processedLines keep all the original lines from <src>.\n // If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines\n // with Platforma Tengo lib and template usages, resolving local names (\":<item>\") to\n // global (\"@milaboratory/pkg:<item>\")\n const processedLines: string[] = [];\n let parserContext: sourceParserContext = {\n isInCommentBlock: false,\n canDetectOptions: true,\n artifactImportREs: new Map<string, [ArtifactType, RegExp][]>(),\n importLikeREs: new Map<string, [ArtifactType, RegExp][]>(),\n multilineStatement: \"\",\n lineNo: 0,\n };\n\n for (const line of lines) {\n parserContext.lineNo++;\n\n try {\n const {\n line: processedLine,\n context: newContext,\n artifacts,\n option,\n } = parseSingleSourceLine(logger, line, parserContext, fullSourceName.pkg, globalizeImports);\n processedLines.push(processedLine);\n parserContext = newContext;\n\n for (const artifact of artifacts ?? []) {\n dependencySet.add(artifact);\n }\n if (option) {\n optionList.push(option);\n }\n } catch (error: unknown) {\n const err = error as Error;\n throw new Error(\n `[line ${parserContext.lineNo} in ${fullNameToString(fullSourceName)}]: ${err.message}\\n\\t${line}`,\n { cause: err },\n );\n }\n }\n\n return {\n normalized: processedLines.join(\"\\n\"),\n deps: dependencySet,\n opts: optionList,\n };\n}\n\nexport type sourceParserContext = {\n isInCommentBlock: boolean;\n canDetectOptions: boolean;\n artifactImportREs: Map<string, [ArtifactType, RegExp][]>;\n importLikeREs: Map<string, [ArtifactType, RegExp][]>;\n multilineStatement: string;\n lineNo: number;\n};\n\nexport type lineProcessingResult = {\n line: string;\n context: sourceParserContext;\n artifacts: TypedArtifactName[];\n option: CompilerOption | undefined;\n};\n\nexport function parseSingleSourceLine(\n logger: MiLogger,\n line: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (context.isInCommentBlock) {\n if (multilineCommentEndRE.exec(line)) {\n context.isInCommentBlock = false;\n }\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n if (compilerOptionRE.exec(line)) {\n if (!context.canDetectOptions) {\n logger.error(\n `[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`,\n );\n throw new Error(\n \"tengo compiler options ('//tengo:' comments) can be set only in file header\",\n );\n }\n return { line, context, artifacts: [], option: parseComplierOption(line) };\n }\n\n if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {\n logger.warn(\n `[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`,\n );\n return { line, context, artifacts: [], option: undefined };\n }\n\n if (singlelineCommentRE.test(line) || singlelineTerminatedCommentRE.test(line)) {\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const canBeInlinedComment = line.includes(\"*/\");\n if (multilineCommentStartRE.exec(line) && !canBeInlinedComment) {\n context.isInCommentBlock = true;\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const statement = context.multilineStatement + line.trim();\n\n const mayContainAComment = line.includes(\"//\") || line.includes(\"/*\");\n if (multilineStatementRE.test(line) && !mayContainAComment) {\n // We accumulate multiline statements into single line before analyzing them.\n // This dramatically simplifies parsing logic: things like\n //\n // assets.\n // importSoftware(\"a:b\");\n //\n // become simple 'assets.importSoftware(\"a:b\");' for parser checks.\n //\n // For safety reasons, we never consider anything that 'may look like a comment'\n // as a part of multiline statement to prevent joining things like\n //\n // someFnCall() // looks like multiline statement because of dot in the end of a comment.\n //\n // This problem also appears in multiline string literals, but I hope this will not\n // cause problems in real life.\n\n // We still try to process each line to globalize imports in case of complex constructions, when\n // statements are stacked one into another:\n // a.\n // use(assets.importSoftware(\":soft1\")).\n // use(assets.importSoftware(\":soft2\")).\n // run()\n // It is multiline, and it still requires import globalization mid-way, not just for the last line of statement\n const result = processAssetImport(line, statement, context, localPackageName, globalizeImports);\n context.multilineStatement += result.line.trim(); // accumulate the line after imports globalization.\n return result;\n }\n\n context.multilineStatement = \"\"; // reset accumulated multiline statement parts once we reach statement end.\n\n if (emptyLineRE.exec(statement)) {\n return { line, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n return processAssetImport(line, statement, context, localPackageName, globalizeImports);\n}\n\nfunction processModuleImport(\n importInstruction: RegExpExecArray,\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n const iInfo = parseImport(statement);\n\n // If we have plapi, ll or assets, then try to parse\n // getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.\n\n if (iInfo.module === \"plapi\") {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newGetTemplateIdRE(iInfo.alias)],\n [\"software\", newGetSoftwareInfoRE(iInfo.alias)],\n ]);\n }\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:ll\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:ll\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":ll\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n ]);\n }\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:assets\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:assets\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":assets\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n [\"asset\", newImportAssetRE(iInfo.alias)],\n [\"wasm\", newImportWasmRE(iInfo.alias)],\n ]);\n context.importLikeREs.set(iInfo.module, [\n [\"template\", newImportTemplateDetector(iInfo.alias)],\n [\"software\", newImportSoftwareDetector(iInfo.alias)],\n [\"asset\", newImportAssetDetector(iInfo.alias)],\n [\"wasm\", newImportWasmDetector(iInfo.alias)],\n ]);\n }\n }\n\n const artifact = parseArtifactName(iInfo.module, \"library\", localPackageName);\n if (!artifact) {\n // not a Platforma Tengo library import\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (globalizeImports) {\n originalLine = originalLine.replace(\n importInstruction[0],\n ` := import(\"${artifact.pkg}:${artifact.id}\")`,\n );\n }\n\n return { line: originalLine, context, artifacts: [artifact], option: undefined };\n}\n\nfunction processAssetImport(\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (emptyLineRE.exec(statement)) {\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n const importInstruction = importRE.exec(statement);\n\n if (importInstruction) {\n return processModuleImport(\n importInstruction,\n originalLine,\n statement,\n context,\n localPackageName,\n globalizeImports,\n );\n }\n\n if (context.artifactImportREs.size > 0) {\n for (const [_, artifactRE] of context.artifactImportREs) {\n for (const [artifactType, re] of artifactRE) {\n // Find all matches in the statement\n const matches = Array.from(statement.matchAll(re));\n if (matches.length === 0) {\n continue;\n }\n\n const artifacts: TypedArtifactName[] = [];\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n if (!match || !match.groups) {\n continue;\n }\n\n const { fnCall, templateName, fnName } = match.groups;\n\n if (!fnCall || !templateName || !fnName) {\n throw Error(`failed to parse template import statement`);\n }\n\n const artifact = parseArtifactName(templateName, artifactType, localPackageName);\n if (!artifact) {\n throw Error(`failed to parse artifact name in ${fnName} import statement`);\n }\n artifacts.push(artifact);\n\n if (globalizeImports) {\n // Replace all occurrences of this fnCall in originalLine\n originalLine = originalLine.replaceAll(\n fnCall,\n `${fnName}(\"${artifact.pkg}:${artifact.id}\")`,\n );\n }\n }\n\n return { line: originalLine, context, artifacts, option: undefined };\n }\n }\n }\n\n if (context.importLikeREs.size > 0) {\n for (const [_, artifactRE] of context.importLikeREs) {\n for (const [artifactType, re] of artifactRE) {\n const match = re.exec(statement);\n if (!match || !match.groups) {\n continue;\n }\n\n throw Error(\n `incorrect '${artifactType}' import statement: use string literal as ID (variables are not allowed) in the same line with brackets (i.e. 'importSoftware(\"sw:main\")').`,\n );\n }\n }\n }\n\n return { line: originalLine, context, artifacts: [], option: undefined };\n}\n\ninterface ImportInfo {\n module: string; // the module name without wrapping quotes: import(\"<module>\")\n alias: string; // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n}\n\nfunction parseImport(line: string): ImportInfo {\n const match = importNameRE.exec(line);\n\n if (!match || !match.groups) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n const { importName, moduleName } = match.groups;\n if (!importName || !moduleName) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n return {\n module: moduleName, // the module name without wrapping quotes: import(\"<module>\")\n alias: importName, // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n };\n}\n\nfunction parseArtifactName(\n moduleName: string,\n aType: ArtifactType,\n localPackageName: string,\n): TypedArtifactName | undefined {\n const depInfo = dependencyRE.exec(moduleName);\n if (!depInfo) {\n return;\n }\n\n if (!depInfo.groups) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n const { pkgName, depID } = depInfo.groups;\n if (!depID) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n return { type: aType, pkg: pkgName ?? localPackageName, id: depID };\n}\n\nexport function getSha256(source: string): string {\n return createHash(\"sha256\").update(source).digest(\"hex\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"source.js","names":[],"sources":["../../src/compiler/source.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport {\n type TypedArtifactName,\n type FullArtifactName,\n type ArtifactType,\n type CompileMode,\n type CompilerOption,\n fullNameToString,\n} from \"./package\";\nimport type { ArtifactMap } from \"./artifactset\";\nimport { createArtifactNameSet } from \"./artifactset\";\nimport { createHash } from \"node:crypto\";\nimport type { MiLogger } from \"@milaboratories/ts-helpers\";\n\n// matches any valid name in tengo. Don't forget to use '\\b' when needed to limit the boundaries!\nconst namePattern = \"[_a-zA-Z][_a-zA-Z0-9]*\";\n\nconst functionCallRE = (moduleName: string, fnName: string) => {\n // `fnCall` captures from the function name through the first string\n // argument (including the closing quote and any trailing whitespace);\n // the closing-paren-or-comma check is a non-consuming lookahead, so\n // any extra args (`assets.importWasm(\"name\", { memoryLimit: ... })`)\n // survive the rewrite in `compiler.ts` — only the literal is\n // build-time material, anything past it is runtime config.\n return new RegExp(\n `\\\\b${moduleName}\\\\.(?<fnCall>(?<fnName>` +\n fnName +\n `)\\\\s*\\\\(\\\\s*\"(?<templateName>[^\"]+)\"\\\\s*)(?=[,)])`,\n \"g\",\n );\n};\n\nconst functionCallLikeRE = (moduleName: string, fnName: string) => {\n return new RegExp(`\\\\b${moduleName}\\\\.(?<fnName>` + fnName + `)\\\\s*\\\\(`, \"g\");\n};\n\nexport const newGetTemplateIdRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getTemplateId\");\nexport const newGetSoftwareInfoRE = (moduleName: string) =>\n functionCallRE(moduleName, \"getSoftwareInfo\");\n\nconst newImportTemplateRE = (moduleName: string) => functionCallRE(moduleName, \"importTemplate\");\nconst newImportTemplateDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importTemplate\");\nconst newImportSoftwareRE = (moduleName: string) => functionCallRE(moduleName, \"importSoftware\");\nconst newImportSoftwareDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importSoftware\");\nconst newImportAssetRE = (moduleName: string) => functionCallRE(moduleName, \"importAsset\");\nconst newImportAssetDetector = (moduleName: string) =>\n functionCallLikeRE(moduleName, \"importAsset\");\nconst newImportWasmRE = (moduleName: string) => functionCallRE(moduleName, \"importWasm\");\nconst newImportWasmDetector = (moduleName: string) => functionCallLikeRE(moduleName, \"importWasm\");\n\nconst emptyLineRE = /^\\s*$/;\nconst compilerOptionRE = /^\\/\\/tengo:[\\w]/;\nconst wrongCompilerOptionRE = /^\\s*\\/\\/\\s*tengo:\\s*./;\nconst singlelineCommentRE = /^\\s*(\\/\\/)/;\nconst singlelineTerminatedCommentRE = /^\\s*\\/\\*.*\\*\\/\\s*$/; // matches '^/* ... */$' comment lines as a special case of singleline comments.\nconst multilineCommentStartRE = /^\\s*\\/\\*/;\nconst multilineCommentEndRE = /\\*\\//;\nconst multilineStatementRE = /[.,]\\s*$/; // it is hard to consistently treat (\\n\"a\"\\n) multiline statements, we forbid them for now.\n\n// import could only be an assignment in a statement,\n// other ways could break a compilation.\nconst importRE = /\\s*:=\\s*import\\s*\\(\\s*\"(?<moduleName>[^\"]+)\"\\s*\\)/;\nconst importNameRE = new RegExp(\n `\\\\b(?<importName>${namePattern}(\\\\.${namePattern})*)${importRE.source}`,\n);\nconst dependencyRE = /(?<pkgName>[^\"]+)?:(?<depID>[^\"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID\n\n/**\n * Parse compiler option string representation\n * Compiler option line is a comment starting with '//tengo:', say\n * //tengo:hash_override tralala\n *\n * The common compiler option syntax is:\n * //tengo:<option name> [<option arg1> [<option arg 2> [...]]]\n */\nconst parseComplierOption = (opt: string): CompilerOption => {\n const parts = opt.split(\" \");\n const namePart = parts[0].split(\":\");\n if (namePart.length != 2) {\n throw new Error(\n \"compiler option format is wrong: expect to have option name after 'tengo:' prefix, like 'tengo:MyOption'\",\n );\n }\n const optName = namePart[1];\n\n return {\n name: optName,\n args: parts.slice(1),\n };\n};\n\nexport class ArtifactSource {\n constructor(\n /** The mode this artifact was built (dev or dist) */\n public readonly compileMode: CompileMode,\n /** Full artifact id, including package version */\n public readonly fullName: FullArtifactName,\n /** Hash of the source code */\n public readonly sourceHash: string,\n /** Normalized source code */\n public readonly src: string,\n /** Path to source file where artifact came from */\n public readonly srcName: string,\n /** List of dependencies */\n public readonly dependencies: TypedArtifactName[],\n /** Additional compiler options detected in source code */\n public readonly compilerOptions: CompilerOption[],\n ) {}\n}\n\nexport function parseSourceFile(\n logger: MiLogger,\n mode: CompileMode,\n srcFile: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const src = readFileSync(srcFile).toString();\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n srcFile,\n deps.array,\n opts,\n );\n}\n\nexport function parseSource(\n logger: MiLogger,\n mode: CompileMode,\n src: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n \"\",\n deps.array,\n opts,\n );\n}\n\n/**\n * Reads src\n * returns normalized source code,\n * gets dependencies from imports,\n * maps imports to global names if globalizeImports is true,\n * and collects compiler options like hashOverride.\n */\nfunction parseSourceData(\n logger: MiLogger,\n src: string,\n fullSourceName: FullArtifactName,\n globalizeImports: boolean,\n): {\n normalized: string;\n deps: ArtifactMap<TypedArtifactName>;\n opts: CompilerOption[];\n} {\n const dependencySet = createArtifactNameSet();\n const optionList: CompilerOption[] = [];\n\n // iterating over lines\n const lines = src.split(\"\\n\");\n\n // processedLines keep all the original lines from <src>.\n // If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines\n // with Platforma Tengo lib and template usages, resolving local names (\":<item>\") to\n // global (\"@milaboratory/pkg:<item>\")\n const processedLines: string[] = [];\n let parserContext: sourceParserContext = {\n isInCommentBlock: false,\n canDetectOptions: true,\n artifactImportREs: new Map<string, [ArtifactType, RegExp][]>(),\n importLikeREs: new Map<string, [ArtifactType, RegExp][]>(),\n multilineStatement: \"\",\n lineNo: 0,\n };\n\n for (const line of lines) {\n parserContext.lineNo++;\n\n try {\n const {\n line: processedLine,\n context: newContext,\n artifacts,\n option,\n } = parseSingleSourceLine(logger, line, parserContext, fullSourceName.pkg, globalizeImports);\n processedLines.push(processedLine);\n parserContext = newContext;\n\n for (const artifact of artifacts ?? []) {\n dependencySet.add(artifact);\n }\n if (option) {\n optionList.push(option);\n }\n } catch (error: unknown) {\n const err = error as Error;\n throw new Error(\n `[line ${parserContext.lineNo} in ${fullNameToString(fullSourceName)}]: ${err.message}\\n\\t${line}`,\n { cause: err },\n );\n }\n }\n\n return {\n normalized: processedLines.join(\"\\n\"),\n deps: dependencySet,\n opts: optionList,\n };\n}\n\nexport type sourceParserContext = {\n isInCommentBlock: boolean;\n canDetectOptions: boolean;\n artifactImportREs: Map<string, [ArtifactType, RegExp][]>;\n importLikeREs: Map<string, [ArtifactType, RegExp][]>;\n multilineStatement: string;\n lineNo: number;\n};\n\nexport type lineProcessingResult = {\n line: string;\n context: sourceParserContext;\n artifacts: TypedArtifactName[];\n option: CompilerOption | undefined;\n};\n\nexport function parseSingleSourceLine(\n logger: MiLogger,\n line: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (context.isInCommentBlock) {\n if (multilineCommentEndRE.exec(line)) {\n context.isInCommentBlock = false;\n }\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n if (compilerOptionRE.exec(line)) {\n if (!context.canDetectOptions) {\n logger.error(\n `[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`,\n );\n throw new Error(\n \"tengo compiler options ('//tengo:' comments) can be set only in file header\",\n );\n }\n return { line, context, artifacts: [], option: parseComplierOption(line) };\n }\n\n if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {\n logger.warn(\n `[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`,\n );\n return { line, context, artifacts: [], option: undefined };\n }\n\n if (singlelineCommentRE.test(line) || singlelineTerminatedCommentRE.test(line)) {\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const canBeInlinedComment = line.includes(\"*/\");\n if (multilineCommentStartRE.exec(line) && !canBeInlinedComment) {\n context.isInCommentBlock = true;\n return { line: \"\", context, artifacts: [], option: undefined };\n }\n\n const statement = context.multilineStatement + line.trim();\n\n const mayContainAComment = line.includes(\"//\") || line.includes(\"/*\");\n if (multilineStatementRE.test(line) && !mayContainAComment) {\n // We accumulate multiline statements into single line before analyzing them.\n // This dramatically simplifies parsing logic: things like\n //\n // assets.\n // importSoftware(\"a:b\");\n //\n // become simple 'assets.importSoftware(\"a:b\");' for parser checks.\n //\n // For safety reasons, we never consider anything that 'may look like a comment'\n // as a part of multiline statement to prevent joining things like\n //\n // someFnCall() // looks like multiline statement because of dot in the end of a comment.\n //\n // This problem also appears in multiline string literals, but I hope this will not\n // cause problems in real life.\n\n // We still try to process each line to globalize imports in case of complex constructions, when\n // statements are stacked one into another:\n // a.\n // use(assets.importSoftware(\":soft1\")).\n // use(assets.importSoftware(\":soft2\")).\n // run()\n // It is multiline, and it still requires import globalization mid-way, not just for the last line of statement\n const result = processAssetImport(line, statement, context, localPackageName, globalizeImports);\n context.multilineStatement += result.line.trim(); // accumulate the line after imports globalization.\n return result;\n }\n\n context.multilineStatement = \"\"; // reset accumulated multiline statement parts once we reach statement end.\n\n if (emptyLineRE.exec(statement)) {\n return { line, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n return processAssetImport(line, statement, context, localPackageName, globalizeImports);\n}\n\nfunction processModuleImport(\n importInstruction: RegExpExecArray,\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n const iInfo = parseImport(statement);\n\n // If we have plapi, ll or assets, then try to parse\n // getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.\n\n if (iInfo.module === \"plapi\") {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newGetTemplateIdRE(iInfo.alias)],\n [\"software\", newGetSoftwareInfoRE(iInfo.alias)],\n ]);\n }\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:ll\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:ll\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":ll\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n ]);\n }\n }\n\n if (\n iInfo.module === \"@milaboratory/tengo-sdk:assets\" ||\n iInfo.module === \"@platforma-sdk/workflow-tengo:assets\" ||\n ((localPackageName === \"@milaboratory/tengo-sdk\" ||\n localPackageName === \"@platforma-sdk/workflow-tengo\") &&\n iInfo.module === \":assets\")\n ) {\n if (!context.artifactImportREs.has(iInfo.module)) {\n context.artifactImportREs.set(iInfo.module, [\n [\"template\", newImportTemplateRE(iInfo.alias)],\n [\"software\", newImportSoftwareRE(iInfo.alias)],\n [\"asset\", newImportAssetRE(iInfo.alias)],\n [\"wasm\", newImportWasmRE(iInfo.alias)],\n ]);\n context.importLikeREs.set(iInfo.module, [\n [\"template\", newImportTemplateDetector(iInfo.alias)],\n [\"software\", newImportSoftwareDetector(iInfo.alias)],\n [\"asset\", newImportAssetDetector(iInfo.alias)],\n [\"wasm\", newImportWasmDetector(iInfo.alias)],\n ]);\n }\n }\n\n const artifact = parseArtifactName(iInfo.module, \"library\", localPackageName);\n if (!artifact) {\n // not a Platforma Tengo library import\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n if (globalizeImports) {\n originalLine = originalLine.replace(\n importInstruction[0],\n ` := import(\"${artifact.pkg}:${artifact.id}\")`,\n );\n }\n\n return { line: originalLine, context, artifacts: [artifact], option: undefined };\n}\n\nfunction processAssetImport(\n originalLine: string,\n statement: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): lineProcessingResult {\n if (emptyLineRE.exec(statement)) {\n return { line: originalLine, context, artifacts: [], option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n const importInstruction = importRE.exec(statement);\n\n if (importInstruction) {\n return processModuleImport(\n importInstruction,\n originalLine,\n statement,\n context,\n localPackageName,\n globalizeImports,\n );\n }\n\n if (context.artifactImportREs.size > 0) {\n for (const [_, artifactRE] of context.artifactImportREs) {\n for (const [artifactType, re] of artifactRE) {\n // Find all matches in the statement\n const matches = Array.from(statement.matchAll(re));\n if (matches.length === 0) {\n continue;\n }\n\n const artifacts: TypedArtifactName[] = [];\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n if (!match || !match.groups) {\n continue;\n }\n\n const { fnCall, templateName, fnName } = match.groups;\n\n if (!fnCall || !templateName || !fnName) {\n throw Error(`failed to parse template import statement`);\n }\n\n const artifact = parseArtifactName(templateName, artifactType, localPackageName);\n if (!artifact) {\n throw Error(`failed to parse artifact name in ${fnName} import statement`);\n }\n artifacts.push(artifact);\n\n if (globalizeImports) {\n // Replace all occurrences of this fnCall in originalLine.\n // fnCall ends right after the literal's closing quote + ws;\n // the trailing `)` or `,` is preserved from the original\n // line, so multi-arg calls (`fn(\"name\", opts)`) keep their\n // remaining args intact.\n originalLine = originalLine.replaceAll(\n fnCall,\n `${fnName}(\"${artifact.pkg}:${artifact.id}\"`,\n );\n }\n }\n\n return { line: originalLine, context, artifacts, option: undefined };\n }\n }\n }\n\n if (context.importLikeREs.size > 0) {\n for (const [_, artifactRE] of context.importLikeREs) {\n for (const [artifactType, re] of artifactRE) {\n const match = re.exec(statement);\n if (!match || !match.groups) {\n continue;\n }\n\n throw Error(\n `incorrect '${artifactType}' import statement: use string literal as ID (variables are not allowed) in the same line with brackets (i.e. 'importSoftware(\"sw:main\")').`,\n );\n }\n }\n }\n\n return { line: originalLine, context, artifacts: [], option: undefined };\n}\n\ninterface ImportInfo {\n module: string; // the module name without wrapping quotes: import(\"<module>\")\n alias: string; // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n}\n\nfunction parseImport(line: string): ImportInfo {\n const match = importNameRE.exec(line);\n\n if (!match || !match.groups) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n const { importName, moduleName } = match.groups;\n if (!importName || !moduleName) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n return {\n module: moduleName, // the module name without wrapping quotes: import(\"<module>\")\n alias: importName, // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n };\n}\n\nfunction parseArtifactName(\n moduleName: string,\n aType: ArtifactType,\n localPackageName: string,\n): TypedArtifactName | undefined {\n const depInfo = dependencyRE.exec(moduleName);\n if (!depInfo) {\n return;\n }\n\n if (!depInfo.groups) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n const { pkgName, depID } = depInfo.groups;\n if (!depID) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n return { type: aType, pkg: pkgName ?? localPackageName, id: depID };\n}\n\nexport function getSha256(source: string): string {\n return createHash(\"sha256\").update(source).digest(\"hex\");\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/tengo-builder",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "description": "Pl Tengo Template Builder",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -25,10 +25,10 @@
25
25
  "@vitest/coverage-istanbul": "^4.1.3",
26
26
  "typescript": "~5.9.3",
27
27
  "vitest": "^4.1.3",
28
- "@milaboratories/build-configs": "2.0.0",
29
- "@milaboratories/ts-configs": "1.2.3",
30
28
  "@milaboratories/ts-builder": "1.5.0",
31
- "@milaboratories/oclif-index": "1.1.1"
29
+ "@milaboratories/oclif-index": "1.1.1",
30
+ "@milaboratories/build-configs": "2.0.0",
31
+ "@milaboratories/ts-configs": "1.2.3"
32
32
  },
33
33
  "oclif": {
34
34
  "bin": "pl-tengo",
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as path from "node:path";
4
4
  import * as fs from "node:fs";
5
+ import * as zlib from "node:zlib";
5
6
  import { pathType } from "./util";
6
7
  import type { TemplatesAndLibs } from "./compiler";
7
8
  import { TengoTemplateCompiler } from "./compiler";
@@ -424,15 +425,24 @@ function addWasmFile(
424
425
  fullName: FullArtifactName,
425
426
  compiler: TengoTemplateCompiler,
426
427
  ) {
427
- // wasm bytes are binary, but hashToSource carries strings only. We base64-encode
428
- // the bytes; the sourceHash is sha256 of the base64 string so it stays consistent
429
- // with the existing `hashToSource[hash] === stored value` invariant.
430
- const bytes = fs.readFileSync(file);
431
- assertWasmFileSize(file, bytes.length, fullName);
432
- const source = bytes.toString("base64");
428
+ // wasm bytes are binary, but hashToSource carries strings only. The file is
429
+ // gzipped first (level 9 — block builds run rarely, so paying the slow-but-
430
+ // tight setting is fine) and then base64-encoded. The backend's wasm package
431
+ // sniffs the gzip header at PrecompileComponent time and gunzips before
432
+ // handing the bytes to wasmtime. Compressing here shrinks both the per-WASM
433
+ // resource footprint (a real wasm component compresses to ~30-40 % of its
434
+ // raw size) and the on-wire pack, which lets pframes-rs grow past the
435
+ // 3 MiB raw-size ceiling without hitting the backend's value-resource cap.
436
+ const raw = fs.readFileSync(file);
437
+ const compressed = zlib.gzipSync(raw, { level: zlib.constants.Z_BEST_COMPRESSION });
438
+ assertWasmFileSize(file, compressed.length, fullName);
439
+ const source = compressed.toString("base64");
433
440
  const wasm = new ArtifactSource(mode, fullName, getSha256(source), source, file, [], []);
434
441
 
435
- logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
442
+ logger.debug(
443
+ `Adding dependency ${fullNameToString(fullName)} from ${file} ` +
444
+ `(${raw.length} B raw → ${compressed.length} B gzipped)`,
445
+ );
436
446
  compiler.addWasm(wasm);
437
447
  }
438
448
 
@@ -50,9 +50,9 @@ describe("assertTemplatePackSize", () => {
50
50
  let err: unknown;
51
51
  try {
52
52
  assertTemplatePackSize("@t/pkg:main 1.0.0", MAX_TEMPLATE_PACK_BYTES_GZIPPED + 1, [
53
- { name: "@small/wasm:main", rawBytes: 100 * 1024 },
54
- { name: "@big/wasm:main", rawBytes: 1.5 * 1024 * 1024 },
55
- { name: "@mid/wasm:main", rawBytes: 800 * 1024 },
53
+ { name: "@small/wasm:main", storedBytes: 100 * 1024 },
54
+ { name: "@big/wasm:main", storedBytes: 1.5 * 1024 * 1024 },
55
+ { name: "@mid/wasm:main", storedBytes: 800 * 1024 },
56
56
  ]);
57
57
  } catch (e) {
58
58
  err = e;
@@ -91,8 +91,8 @@ describe("collectWasmContributions", () => {
91
91
  return "A".repeat(len);
92
92
  }
93
93
 
94
- it("reports direct WASM dependencies with raw byte size derived from base64 length", () => {
95
- const base64 = base64OfLength(400); // 400 base64 chars → 300 raw bytes
94
+ it("reports direct WASM dependencies with stored byte size derived from base64 length", () => {
95
+ const base64 = base64OfLength(400); // 400 base64 chars → 300 binary bytes
96
96
  const tpl: CompiledTemplateV3 = {
97
97
  type: "pl.tengo-template.v3",
98
98
  hashToSource: { "hash-a": base64 },
@@ -110,12 +110,12 @@ describe("collectWasmContributions", () => {
110
110
  },
111
111
  };
112
112
  const got = collectWasmContributions(tpl);
113
- expect(got).toEqual([{ name: "@w/wasm:a", rawBytes: 300 }]);
113
+ expect(got).toEqual([{ name: "@w/wasm:a", storedBytes: 300 }]);
114
114
  });
115
115
 
116
116
  it("recurses into sub-templates and deduplicates by artefact name", () => {
117
- const base64a = base64OfLength(800); // 600 raw
118
- const base64b = base64OfLength(400); // 300 raw
117
+ const base64a = base64OfLength(800); // 600 binary bytes
118
+ const base64b = base64OfLength(400); // 300 binary bytes
119
119
  const tpl: CompiledTemplateV3 = {
120
120
  type: "pl.tengo-template.v3",
121
121
  hashToSource: { "hash-a": base64a, "hash-b": base64b },
@@ -149,8 +149,8 @@ describe("collectWasmContributions", () => {
149
149
  };
150
150
  const got = collectWasmContributions(tpl).sort((a, b) => a.name.localeCompare(b.name));
151
151
  expect(got).toEqual([
152
- { name: "@w/wasm:a", rawBytes: 600 },
153
- { name: "@w/wasm:b", rawBytes: 300 },
152
+ { name: "@w/wasm:a", storedBytes: 600 },
153
+ { name: "@w/wasm:b", storedBytes: 300 },
154
154
  ]);
155
155
  });
156
156
 
@@ -17,11 +17,16 @@ import { fullNameToString } from "./package";
17
17
  // 3.5 MiB per gzipped template pack, checked before the pack itself is
18
18
  // stored as a TengoTemplatePackV1 value resource.
19
19
 
20
- // 2 MiB raw → ~2.67 MiB base64 + JSON wrapper → comfortably under the 3 MiB
21
- // per-value-resource cap with ~330 KiB headroom for the WasmV1Data wrapper
22
- // (Name, Version, Runtime, DefaultMemoryLimit, JSON syntax). WasmV1Data.Code
23
- // is a Go `[]byte`, which encoding/json serialises as base64 — that's where
24
- // the 4/3 expansion comes from.
20
+ // Cap on the gzipped wasm payload that ends up in WasmV1Data.Code on the
21
+ // backend. 2 MiB gzipped → ~2.67 MiB base64 + JSON wrapper → comfortably
22
+ // under the 3 MiB per-value-resource cap with ~330 KiB headroom for the
23
+ // WasmV1Data wrapper (Name, Version, Runtime, DefaultMemoryLimit, JSON
24
+ // syntax). WasmV1Data.Code is a Go `[]byte`, which encoding/json serialises
25
+ // as base64 — that's where the 4/3 expansion comes from.
26
+ //
27
+ // The tengo-builder gzips wasm files before adding them to the pack; this
28
+ // cap therefore admits raw .wasm files several times larger than 2 MiB
29
+ // (real wasm components compress to ~30-40 % of their raw size).
25
30
  export const MAX_WASM_FILE_BYTES = 2 * 1024 * 1024;
26
31
 
27
32
  // 100 KiB below the backend's 3.5 MiB so blocks don't break on small
@@ -41,8 +46,8 @@ export function assertWasmFileSize(
41
46
  ): void {
42
47
  if (byteLength <= MAX_WASM_FILE_BYTES) return;
43
48
  throw new Error(
44
- `WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)}, ` +
45
- `which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. ` +
49
+ `WASM artefact ${fullNameToString(fullName)} from ${file} is ${formatBytes(byteLength)} ` +
50
+ `gzipped, which exceeds tengo-builder's ${formatBytes(MAX_WASM_FILE_BYTES)} per-WASM cap. ` +
46
51
  `The backend stores each WASM as a single value resource (3 MiB hard cap after base64+JSON ` +
47
52
  `marshal — see maxResourceDataSize in pl: platform/core/transaction/assertions.go). ` +
48
53
  `Strip debug info or run \`wasm-opt -Oz\` to shrink it.`,
@@ -52,8 +57,13 @@ export function assertWasmFileSize(
52
57
  export interface WasmContribution {
53
58
  /** Artefact name as stored under TemplateDataV3.wasm (e.g. "@pkg:id"). */
54
59
  readonly name: string;
55
- /** Raw WASM bytes — decoded from the base64-encoded source in hashToSource. */
56
- readonly rawBytes: number;
60
+ /**
61
+ * Bytes this artefact contributes to the pack, measured after gzip and
62
+ * before base64 — i.e. the size of the binary payload stored on the
63
+ * backend in WasmV1Data.Code. Decoded from the base64-encoded source in
64
+ * hashToSource.
65
+ */
66
+ readonly storedBytes: number;
57
67
  }
58
68
 
59
69
  /**
@@ -69,10 +79,10 @@ export function collectWasmContributions(tpl: CompiledTemplateV3): WasmContribut
69
79
  for (const [name, ref] of Object.entries(t.wasm ?? {})) {
70
80
  if (seen.has(name)) continue;
71
81
  const base64 = tpl.hashToSource[ref.sourceHash];
72
- // base64 encodes 3 raw bytes per 4 chars; the off-by-padding is at most
73
- // 2 bytes per artefact — fine for a human-readable size breakdown.
74
- const rawBytes = base64 != null ? Math.floor((base64.length * 3) / 4) : 0;
75
- seen.set(name, { name, rawBytes });
82
+ // base64 encodes 3 binary bytes per 4 chars; the off-by-padding is at
83
+ // most 2 bytes per artefact — fine for a human-readable size breakdown.
84
+ const storedBytes = base64 != null ? Math.floor((base64.length * 3) / 4) : 0;
85
+ seen.set(name, { name, storedBytes });
76
86
  }
77
87
  for (const sub of Object.values(t.templates ?? {})) walk(sub);
78
88
  }
@@ -86,12 +96,12 @@ export function assertTemplatePackSize(
86
96
  wasmContributions: readonly WasmContribution[],
87
97
  ): void {
88
98
  if (gzippedByteLength <= MAX_TEMPLATE_PACK_BYTES_GZIPPED) return;
89
- const ranked = [...wasmContributions].sort((a, b) => b.rawBytes - a.rawBytes);
99
+ const ranked = [...wasmContributions].sort((a, b) => b.storedBytes - a.storedBytes);
90
100
  const breakdown =
91
101
  ranked.length === 0
92
102
  ? "\n (no WASM artefacts in this pack — heavy libs, software descriptors, or sub-templates are the likely cause.)"
93
- : "\nWASM artefacts in this pack (raw bytes):\n" +
94
- ranked.map((w) => ` - ${w.name} — ${formatBytes(w.rawBytes)}`).join("\n");
103
+ : "\nWASM artefacts in this pack (gzipped, pre-base64):\n" +
104
+ ranked.map((w) => ` - ${w.name} — ${formatBytes(w.storedBytes)}`).join("\n");
95
105
  throw new Error(
96
106
  `Template pack ${templateName} is ${formatBytes(gzippedByteLength)} gzipped, ` +
97
107
  `which exceeds tengo-builder's ${formatBytes(MAX_TEMPLATE_PACK_BYTES_GZIPPED)} per-pack cap. ` +
@@ -156,6 +156,36 @@ describe("import statements", () => {
156
156
  "variables are not allowed",
157
157
  );
158
158
  });
159
+
160
+ test("assets.importWasm with extra positional args keeps trailing args intact", () => {
161
+ // MILAB-6145: importWasm gained an optional 2nd opts arg
162
+ // (e.g. assets.importWasm("name", { memoryLimit: ... })). The build-
163
+ // time rewrite must preserve the trailing args — previously the
164
+ // substitution wrote its own `)` and corrupted multi-arg calls into
165
+ // syntactically broken output like `importWasm("normalized") opts)`.
166
+ const logger = createLogger("error");
167
+ const wasmImportWithOpts = `
168
+ assets := import("@platforma-sdk/workflow-tengo:assets")
169
+ opts := { memoryLimit: 50 * 1024 * 1024 }
170
+ wasm := assets.importWasm("@milaboratories/pframes-rs-wasip2:main", opts)
171
+ `;
172
+
173
+ const parsed = parseSource(logger, "dist", wasmImportWithOpts, stubTplName, true);
174
+
175
+ // The dependency is still discovered from the literal.
176
+ expect(parsed.dependencies).toContainEqual({
177
+ type: "wasm",
178
+ pkg: "@milaboratories/pframes-rs-wasip2",
179
+ id: "main",
180
+ });
181
+
182
+ // The rewritten source still calls importWasm with two args; the
183
+ // `, opts)` tail survives the rewrite. The normalized form replaces
184
+ // the package literal in place but leaves the closing tokens alone.
185
+ expect(parsed.src).toContain(`importWasm("@milaboratories/pframes-rs-wasip2:main", opts)`);
186
+ // No stray `) opts)` from the old broken substitution.
187
+ expect(parsed.src).not.toMatch(/\)\s*opts\)/);
188
+ });
159
189
  });
160
190
 
161
191
  describe("parseSingleSourceLine", () => {
@@ -16,10 +16,16 @@ import type { MiLogger } from "@milaboratories/ts-helpers";
16
16
  const namePattern = "[_a-zA-Z][_a-zA-Z0-9]*";
17
17
 
18
18
  const functionCallRE = (moduleName: string, fnName: string) => {
19
+ // `fnCall` captures from the function name through the first string
20
+ // argument (including the closing quote and any trailing whitespace);
21
+ // the closing-paren-or-comma check is a non-consuming lookahead, so
22
+ // any extra args (`assets.importWasm("name", { memoryLimit: ... })`)
23
+ // survive the rewrite in `compiler.ts` — only the literal is
24
+ // build-time material, anything past it is runtime config.
19
25
  return new RegExp(
20
26
  `\\b${moduleName}\\.(?<fnCall>(?<fnName>` +
21
27
  fnName +
22
- `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*\\))`,
28
+ `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*)(?=[,)])`,
23
29
  "g",
24
30
  );
25
31
  };
@@ -454,10 +460,14 @@ function processAssetImport(
454
460
  artifacts.push(artifact);
455
461
 
456
462
  if (globalizeImports) {
457
- // Replace all occurrences of this fnCall in originalLine
463
+ // Replace all occurrences of this fnCall in originalLine.
464
+ // fnCall ends right after the literal's closing quote + ws;
465
+ // the trailing `)` or `,` is preserved from the original
466
+ // line, so multi-arg calls (`fn("name", opts)`) keep their
467
+ // remaining args intact.
458
468
  originalLine = originalLine.replaceAll(
459
469
  fnCall,
460
- `${fnName}("${artifact.pkg}:${artifact.id}")`,
470
+ `${fnName}("${artifact.pkg}:${artifact.id}"`,
461
471
  );
462
472
  }
463
473
  }