UNPKG

@opentui/core

Version:

OpenTUI is a TypeScript library on a native Zig core for building terminal user interfaces (TUIs)

265 lines (254 loc) 8.47 kB
// src/node-assets.ts import { statSync } from "node:fs"; import { dirname, join as join2, resolve } from "node:path"; import { fileURLToPath } from "node:url"; // src/node-asset-target.ts var NATIVE_FILE_NAMES = { darwin: "libopentui.dylib", linux: "libopentui.so", win32: "opentui.dll" }; function getNativeAssetDescriptor(target) { if (!Object.hasOwn(NATIVE_FILE_NAMES, target.platform) || target.arch !== "arm64" && target.arch !== "x64") { throw new Error(`Unsupported OpenTUI Node asset target: ${String(target.platform)}-${String(target.arch)}`); } if (target.libc !== undefined && target.libc !== "glibc" && target.libc !== "musl") { throw new Error(`Unsupported libc for OpenTUI Node assets: ${String(target.libc)}`); } if (target.platform !== "linux" && target.libc !== undefined) { throw new Error(`OpenTUI Node asset target libc is only supported on Linux, got ${target.platform}`); } const libcSuffix = target.platform === "linux" && target.libc === "musl" ? "-musl" : ""; const packageName = `@opentui/core-${target.platform}-${target.arch}${libcSuffix}`; const fileName = NATIVE_FILE_NAMES[target.platform]; return { key: `${packageName}/${fileName}`, packageName, fileName }; } // src/platform/assets.ts import { isAbsolute, join } from "node:path"; // src/lib/singleton.ts var singletonCacheSymbol = Symbol.for("@opentui/core/singleton"); function singleton(key, factory) { const bag = globalThis[singletonCacheSymbol] ??= {}; if (!(key in bag)) { bag[key] = factory(); } return bag[key]; } // src/lib/env.ts var envRegistry = singleton("env-registry", () => ({})); function registerEnvVar(config) { const existing = envRegistry[config.name]; if (existing) { if (existing.description !== config.description || existing.type !== config.type || existing.default !== config.default || existing.required !== config.required) { throw new Error(`Environment variable "${config.name}" is already registered with different configuration. ` + `Existing: ${JSON.stringify(existing)}, New: ${JSON.stringify(config)}`); } return; } envRegistry[config.name] = config; } function normalizeBoolean(value) { const lowerValue = value.toLowerCase(); return ["true", "1", "on", "yes"].includes(lowerValue); } function parseEnvValue(config) { const envValue = process.env[config.name]; if (envValue === undefined && config.default !== undefined) { return config.default; } if (envValue === undefined && config.required === false) { return; } if (envValue === undefined) { throw new Error(`Required environment variable ${config.name} is not set. ${config.description}`); } switch (config.type) { case "boolean": return typeof envValue === "boolean" ? envValue : normalizeBoolean(envValue); case "number": const numValue = Number(envValue); if (isNaN(numValue)) { throw new Error(`Environment variable ${config.name} must be a valid number, got: ${envValue}`); } return numValue; case "string": default: return envValue; } } class EnvStore { parsedValues = new Map; get(key) { if (this.parsedValues.has(key)) { return this.parsedValues.get(key); } if (!(key in envRegistry)) { throw new Error(`Environment variable ${key} is not registered.`); } try { const value = parseEnvValue(envRegistry[key]); this.parsedValues.set(key, value); return value; } catch (error) { throw new Error(`Failed to parse env var ${key}: ${error instanceof Error ? error.message : String(error)}`); } } has(key) { return key in envRegistry; } clearCache() { this.parsedValues.clear(); } } var envStore = singleton("env-store", () => new EnvStore); var env = new Proxy({}, { get(target, prop) { if (typeof prop !== "string") { return; } return envStore.get(prop); }, has(target, prop) { return envStore.has(prop); }, ownKeys() { return Object.keys(envRegistry); }, getOwnPropertyDescriptor(target, prop) { if (envStore.has(prop)) { return { enumerable: true, configurable: true, get: () => envStore.get(prop) }; } return; } }); // src/platform/assets.ts registerEnvVar({ name: "OTUI_ASSET_ROOT", description: "Absolute directory containing relocatable OpenTUI runtime assets", type: "string", default: "" }); function validateAssetKey(key) { if (key.length === 0 || isAbsolute(key) || key.includes("\\") || key.split("/").includes("..")) { throw new Error(`Invalid OpenTUI asset key: ${JSON.stringify(key)}`); } } // src/platform/runtime-assets.node.ts var CORE_ASSET_PREFIX = "@opentui/core/"; var PARSER_WORKER_ASSET_KEY = `${CORE_ASSET_PREFIX}parser.worker.js`; // src/lib/tree-sitter/default-parsers.ts var defaultParserDescriptors = [ { filetype: "javascript", aliases: ["javascriptreact"], queries: { highlights: ["assets/javascript/highlights.scm"] }, wasm: "assets/javascript/tree-sitter-javascript.wasm" }, { filetype: "typescript", aliases: ["typescriptreact"], queries: { highlights: ["assets/typescript/highlights.scm"] }, wasm: "assets/typescript/tree-sitter-typescript.wasm" }, { filetype: "markdown", queries: { highlights: ["assets/markdown/highlights.scm"], injections: ["assets/markdown/injections.scm"] }, wasm: "assets/markdown/tree-sitter-markdown.wasm", injectionMapping: { nodeTypes: { inline: "markdown_inline", pipe_table_cell: "markdown_inline" }, infoStringMap: { javascript: "javascript", js: "javascript", jsx: "javascriptreact", javascriptreact: "javascriptreact", typescript: "typescript", ts: "typescript", tsx: "typescriptreact", typescriptreact: "typescriptreact", markdown: "markdown", md: "markdown" } } }, { filetype: "markdown_inline", queries: { highlights: ["assets/markdown_inline/highlights.scm"] }, wasm: "assets/markdown_inline/tree-sitter-markdown_inline.wasm" }, { filetype: "zig", queries: { highlights: ["assets/zig/highlights.scm"] }, wasm: "assets/zig/tree-sitter-zig.wasm" } ]; var defaultParserAssetPaths = [ ...new Set(defaultParserDescriptors.flatMap((parser) => [ ...parser.queries.highlights, parser.wasm, ...parser.queries.injections ?? [] ])) ]; // src/node-assets.ts var CORE_PREFIX = "@opentui/core/"; var PARSER_WORKER_KEY = `${CORE_PREFIX}parser.worker.js`; var TREE_SITTER_WASM_KEY = "web-tree-sitter/tree-sitter.wasm"; function getNodeAssets(target) { const native = getNativeAssetDescriptor(target); const coreRoot = resolveCoreRuntimeRoot(); const nativeRoot = dirname(resolvePackageEntry(native.packageName)); const assets = [ { key: native.key, source: join2(nativeRoot, native.fileName) }, { key: PARSER_WORKER_KEY, source: join2(coreRoot, "parser.worker.js") }, ...defaultParserAssetPaths.map((relativePath) => ({ key: `${CORE_PREFIX}${relativePath}`, source: join2(coreRoot, relativePath) })), { key: TREE_SITTER_WASM_KEY, source: resolvePackageEntry(TREE_SITTER_WASM_KEY) } ]; const keys = new Set; for (const asset of assets) { validateAssetKey(asset.key); if (keys.has(asset.key)) { throw new Error(`Duplicate OpenTUI Node asset key: ${JSON.stringify(asset.key)}`); } keys.add(asset.key); let isFile = false; try { isFile = statSync(asset.source).isFile(); } catch {} if (!isFile) { throw new Error(`Missing OpenTUI Node asset ${JSON.stringify(asset.key)} at ${JSON.stringify(asset.source)}`); } } return assets.toSorted((left, right) => left.key < right.key ? -1 : left.key > right.key ? 1 : 0); } function resolveCoreRuntimeRoot() { const moduleDirectory = dirname(fileURLToPath(import.meta.url)); const candidates = [moduleDirectory, resolve(moduleDirectory, "../dist")]; return candidates.find((candidate) => statIsFile(join2(candidate, "parser.worker.js"))) ?? moduleDirectory; } function resolvePackageEntry(specifier) { return fileURLToPath(import.meta.resolve(specifier)); } function statIsFile(path) { try { return statSync(path).isFile(); } catch { return false; } } export { getNodeAssets }; //# debugId=2D9AF8B7C6420F5D64756E2164756E21 //# sourceMappingURL=node-assets.js.map