@jk2908/cxx 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/dist/build.d.ts +19 -11
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +204 -82
- package/dist/build.js.map +6 -5
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/next/cxx-loader.cjs +109 -58
- package/dist/next/cxx-loader.cjs.map +7 -7
- package/dist/next/index.d.ts +5 -3
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +219 -107
- package/dist/next/index.js.map +7 -6
- package/dist/types.d.ts +1 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +0 -16
- package/dist/utils.d.ts.map +1 -1
- package/dist/vite/index.d.ts +1 -7
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +240 -247
- package/dist/vite/index.js.map +7 -7
- package/package.json +6 -6
- package/src/build.ts +202 -73
- package/src/logger.ts +2 -7
- package/src/next/cxx-loader.js +8 -1
- package/src/next/index.ts +25 -27
- package/src/types.ts +1 -7
- package/src/utils.ts +0 -79
- package/src/vite/index.ts +60 -100
package/dist/vite/index.js.map
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/build.ts", "../src/config.ts", "../src/
|
|
3
|
+
"sources": ["../src/build.ts", "../src/config.ts", "../src/logger.ts", "../src/lru.ts", "../src/utils.ts", "../src/vite/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { createHash } from 'node:crypto'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { transform } from 'lightningcss'\nimport MagicString, { type SourceMap } from 'magic-string'\n\nimport type { BuildContext, PluginConfig, Tags } from './types.js'\nimport { AUTOGEN_MSG, GENERATED_DIR, PKG_NAME } from './config.js'\nimport { LruCache } from './lru.js'\nimport { pascalise } from './utils.js'\n\n// decode bytes to a string, then stringify into a safe literal. `${bytes}` only\n// works by accident for Buffer; a plain Uint8Array stringifies as `97,123,125`\nconst decoder = new TextDecoder()\n\n/**\n * LRU cache of `collect` results by file id + last seen source + config so watcher and transform\n * can reuse the same parsed template/tags.\n */\nconst collectCache = new LruCache<{\n\tsource: string\n\tconfig: string\n\ttemplate: string\n\ttags: Tags\n\tmap: SourceMap | null\n}>()\n\n/**\n * LRU cache for file content. Stores the last written content per file path so `maybeWrite`\n * can skip disk i/o when nothing has changed.\n */\nconst fileCache = new LruCache<string>()\n\n/**\n * Serialises type file writes inside a single process so overlapping `writeTypes` calls can't\n * interleave or land out of order.\n */\nlet writeChain: Promise<void> = Promise.resolve()\n\n/**\n * Returns whether the error was caused by a missing file or directory.\n */\nexport function isENOENT(err: unknown) {\n\treturn err instanceof Error && 'code' in err && err.code === 'ENOENT'\n}\n\n/**\n * Write a file by first writing to a unique temporary file and then renaming it into place, so\n * concurrent writers (e.g. Turbopack loader workers) never observe a partial file.\n */\nasync function writeFileAtomic(filePath: string, content: string) {\n\tconst tmp = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`\n\n\tawait fs.writeFile(tmp, content)\n\tawait fs.rename(tmp, filePath)\n}\n\n/**\n * Run a write task after all previously queued writes have settled. A rejection doesn't break the\n * chain for later tasks.\n */\nfunction enqueueWrite<T>(task: () => Promise<T>) {\n\t// wait for the previous write to finish, then run this one, even if the previous one failed\n\tconst run = writeChain.then(task, task)\n\n\t// move the queue on to this write, but turn either outcome into success so it never rejects\n\twriteChain = run.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t)\n\n\t// return the real promise, so the caller still sees this write's value or error\n\treturn run\n}\n\n/**\n * Write a file only if the content actually differs from what is already on disk.\n */\nexport async function maybeWrite(filePath: string, content: string) {\n\tconst cached = fileCache.get(filePath)\n\t// fast path: already wrote this exact content in this process\n\tif (cached === content) return false\n\n\t// verify against disk on a cold start (or when the cache is stale) so we\n\t// don't needlessly bump the mtime and invalidate downstream watchers\n\ttry {\n\t\tif ((await fs.readFile(filePath, 'utf-8')) === content) {\n\t\t\tfileCache.set(filePath, content)\n\t\t\treturn false\n\t\t}\n\t} catch (err) {\n\t\tif (!isENOENT(err)) throw err\n\t}\n\n\tawait writeFileAtomic(filePath, content)\n\tfileCache.set(filePath, content)\n\n\treturn true\n}\n\n// matches `[css, classes, href] = cxx\\`...\\`` and `cxx.tag<T>('name')\\`...\\``\n// capture groups: 1 optional `export `, 2-4 assigned variable names, 5 plain\n// css body, 6 quote kind, 7 tag name, 8 tagged css body\nconst regex =\n\t/((?:export\\s+)?)(?:const|var|let)\\s*\\[(\\w*)\\s*,?\\s*(\\w*)\\s*,?\\s*(\\w*)\\s*\\]\\s*=\\s*cxx(?:\\s*`([\\s\\S]*?)`|\\s*\\.\\s*tag(?:\\s*<[^>]+>)?\\s*\\(\\s*(['\"])(.*?)\\6\\s*\\)\\s*`([\\s\\S]*?)`)/gm\n\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/\n\n/**\n * Hash transformed CSS into a stable href for style deduplication.\n */\nfunction hashCss(code: Uint8Array) {\n\treturn `cxx-${createHash('sha256').update(code).digest('base64url').slice(0, 12)}`\n}\n\nexport class DuplicateTagError extends Error {\n\tname = 'DuplicateTagError'\n\n\tconstructor(tag: string) {\n\t\tsuper(`Tag ${tag} has already been seen. Tags must be unique across your application`)\n\t}\n}\n\nexport class InvalidTagError extends Error {\n\tname = 'InvalidTagError'\n\n\tconstructor(tag: string) {\n\t\tsuper(\n\t\t\t`Tag \"${tag}\" does not map to a valid TypeScript identifier. ` +\n\t\t\t\t`Use letters, numbers, spaces, \"_\" or \"-\"`,\n\t\t)\n\t}\n}\n\n/**\n * Transform `cxx` templates in one source file and collect any exported tag types.\n */\nexport function collect(source: string, id: string, config: PluginConfig) {\n\tconst configKey = JSON.stringify(config)\n\n\t// reuse the last result when the source and config are unchanged\n\tconst cached = collectCache.get(id)\n\tif (cached?.source === source && cached.config === configKey) return cached\n\n\tconst tags: Tags = new Map()\n\tconst magic = new MagicString(source)\n\tlet matched = false\n\n\t// the regex is global, so reset its cursor before scanning\n\tregex.lastIndex = 0\n\n\tlet match: RegExpExecArray | null\n\n\t// walk every cxx template and replace it in place\n\twhile ((match = regex.exec(source))) {\n\t\tmatched = true\n\n\t\t// capture groups: export, three bindings, plain css, (quote), tag, tagged css\n\t\tconst [, exp, varOne, varTwo, varThree, plainCss, , tag, taggedCss] = match\n\t\tconst css = plainCss ?? taggedCss\n\n\t\t// compile the CSS to minified CSS Modules\n\t\tconst { code, exports = {} } = transform({\n\t\t\tminify: true,\n\t\t\tcssModules: true,\n\t\t\tfilename: id,\n\t\t\tcode: new TextEncoder().encode(css),\n\t\t})\n\n\t\tconst href = hashCss(code)\n\t\t// map each class name to its generated (scoped) name\n\t\tconst styles = Object.fromEntries(\n\t\t\tObject.entries(exports).map(([k, v]) => [k, v.name]),\n\t\t)\n\n\t\tif (tag) {\n\t\t\tconst suffix =\n\t\t\t\ttypeof config.typeSuffix === 'string'\n\t\t\t\t\t? config.typeSuffix\n\t\t\t\t\t: config.typeSuffix === false\n\t\t\t\t\t\t? ''\n\t\t\t\t\t\t: 'Classes'\n\t\t\tconst tagWithSuffix = pascalise(`${tag}${suffix}`)\n\n\t\t\tif (!IDENTIFIER.test(tagWithSuffix)) throw new InvalidTagError(tag)\n\t\t\tif (tags.has(tagWithSuffix)) throw new DuplicateTagError(tagWithSuffix)\n\n\t\t\t// side effect but necessary\n\t\t\ttags.set(tagWithSuffix, Object.keys(styles))\n\t\t}\n\n\t\tconst statements: string[] = []\n\n\t\tif (varOne) {\n\t\t\tstatements.push(`${exp}const ${varOne} = ${JSON.stringify(decoder.decode(code))}`)\n\t\t}\n\n\t\tif (varTwo) {\n\t\t\tstatements.push(`${exp}const ${varTwo} = ${JSON.stringify(styles)}`)\n\t\t}\n\n\t\tif (varThree) {\n\t\t\tstatements.push(`${exp}const ${varThree} = ${JSON.stringify(href)}`)\n\t\t}\n\n\t\t// swap the template for the generated declarations, keeping the export keyword\n\t\tmagic.overwrite(match.index, match.index + match[0].length, statements.join('\\n'))\n\t}\n\n\tconst template = magic.toString()\n\t// only build a map when something was actually rewritten\n\tconst map = matched\n\t\t? magic.generateMap({ source: id, includeContent: true, hires: true })\n\t\t: null\n\tconst result = { source, config: configKey, template, tags, map }\n\n\tcollectCache.set(id, result)\n\n\treturn result\n}\n\n/**\n * Render the generated declaration file contents for a set of collected tags.\n */\nfunction renderTypes(tags: Tags) {\n\treturn [\n\t\tAUTOGEN_MSG,\n\t\t'',\n\t\t`import '${PKG_NAME}'`,\n\t\t'',\n\t\t`declare module '${PKG_NAME}' {`,\n\t\ttagsToType(tags),\n\t\t'}',\n\t\t'',\n\t].join('\\n')\n}\n\n/**\n * Write (or remove) the generated `index.d.ts` for a full tag surface.\n */\nasync function writeRenderedTypes(tags: Tags) {\n\tconst filePath = path.join(GENERATED_DIR, 'index.d.ts')\n\n\tif (!tags.size) {\n\t\t// `force` makes this a no-op when the file is already absent\n\t\tawait fs.rm(filePath, { force: true })\n\t\tfileCache.delete(filePath)\n\n\t\treturn\n\t}\n\n\tawait fs.mkdir(GENERATED_DIR, { recursive: true })\n\tawait maybeWrite(filePath, renderTypes(tags))\n}\n\n/**\n * Write the generated declaration file for the current set of collected tags.\n */\nexport function writeTypes(tags: Tags) {\n\treturn enqueueWrite(() => writeRenderedTypes(tags))\n}\n\nconst PARTIAL_DIR = path.join(GENERATED_DIR, 'tags')\n\nfunction partialPath(filePath: string) {\n\treturn path.join(\n\t\tPARTIAL_DIR,\n\t\t`${createHash('sha1').update(filePath).digest('hex')}.json`,\n\t)\n}\n\n/**\n * Read every per-file partial written by the Next loader workers and merge them into one tag map.\n * Partials whose source file no longer exists are pruned so deleted files drop out of the types.\n */\nasync function readPartials() {\n\tlet entries: string[]\n\n\ttry {\n\t\tentries = await fs.readdir(PARTIAL_DIR)\n\t} catch (err) {\n\t\tif (isENOENT(err)) return new Map()\n\t\tthrow err\n\t}\n\n\tconst tags: Tags = new Map()\n\n\tfor (const entry of entries) {\n\t\tif (!entry.endsWith('.json')) continue\n\n\t\tconst partial = path.join(PARTIAL_DIR, entry)\n\t\tlet parsed: { file: string; tags: Record<string, string[]> }\n\n\t\ttry {\n\t\t\tparsed = JSON.parse(await fs.readFile(partial, 'utf-8'))\n\t\t} catch {\n\t\t\tcontinue\n\t\t}\n\n\t\ttry {\n\t\t\tawait fs.access(parsed.file)\n\t\t} catch {\n\t\t\tawait fs.rm(partial, { force: true })\n\t\t\tcontinue\n\t\t}\n\n\t\tfor (const [name, classes] of Object.entries(parsed.tags)) {\n\t\t\tif (tags.has(name)) throw new DuplicateTagError(name)\n\t\t\ttags.set(name, classes)\n\t\t}\n\t}\n\n\treturn tags\n}\n\n/**\n * Next-specific write path. Turbopack spreads loaders across worker processes, so each worker\n * persists its own per-file partial and rebuilds the shared declaration file from all of them.\n */\nexport function writeTypesForFile(filePath: string, tags: Tags) {\n\treturn enqueueWrite(async () => {\n\t\tawait fs.mkdir(PARTIAL_DIR, { recursive: true })\n\n\t\tconst partial = partialPath(filePath)\n\n\t\tif (!tags.size) {\n\t\t\tawait fs.rm(partial, { force: true })\n\t\t} else {\n\t\t\tawait writeFileAtomic(\n\t\t\t\tpartial,\n\t\t\t\tJSON.stringify({ file: filePath, tags: Object.fromEntries(tags) }),\n\t\t\t)\n\t\t}\n\n\t\tawait writeRenderedTypes(await readPartials())\n\t})\n}\n\n/**\n * Render collected tags as a module augmentation for the package entrypoint.\n */\nexport function tagsToType(tags: Tags) {\n\treturn [...tags]\n\t\t.map(([tag, classes]) => {\n\t\t\tconst union =\n\t\t\t\tclasses.length > 0\n\t\t\t\t\t? classes\n\t\t\t\t\t\t\t.toSorted((a, b) => a.length - b.length)\n\t\t\t\t\t\t\t.map(c => `'${c}'`)\n\t\t\t\t\t\t\t.join(' | ')\n\t\t\t\t\t: 'never'\n\n\t\t\treturn `\\texport type ${tag} = ${union}`\n\t\t})\n\t\t.join('\\n')\n}\n\n/**\n * Merge per-file tag maps into one application-wide tag map.\n */\nexport function flattenTags(tagsByFile: BuildContext['tagsByFile']) {\n\tconst tags = new Map<string, string[]>()\n\n\tfor (const fileTags of tagsByFile.values()) {\n\t\tfor (const [name, classes] of fileTags) {\n\t\t\tif (tags.has(name)) throw new DuplicateTagError(name)\n\t\t\ttags.set(name, classes)\n\t\t}\n\t}\n\n\treturn tags\n}\n",
|
|
5
|
+
"import type { Dirent } from 'node:fs'\n\nimport { createHash } from 'node:crypto'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { transform } from 'lightningcss'\nimport MagicString, { type SourceMap } from 'magic-string'\n\nimport type { PluginConfig, Tags } from './types.js'\nimport { AUTOGEN_MSG, GENERATED_DIR, NAME, PKG_NAME } from './config.js'\nimport { Logger } from './logger.js'\nimport { LruCache } from './lru.js'\nimport { pascalise } from './utils.js'\n\nconst logger = new Logger(NAME)\n\nconst decoder = new TextDecoder()\nconst encoder = new TextEncoder()\n\n/**\n * LRU cache of `collect` results by file id + last seen source + config so watcher and transform\n * can reuse the same parsed template/tags.\n */\nconst collectCache = new LruCache<{\n\tsource: string\n\tconfig: string\n\ttemplate: string\n\ttags: Tags\n\tmap: SourceMap | null\n}>()\n\n/**\n * Serialises type file writes inside a single process so overlapping writes can't interleave or\n * land out of order.\n */\nlet writeChain: Promise<void> = Promise.resolve()\n\n/**\n * Returns whether the error was caused by a missing file or directory.\n */\nexport function isENOENT(err: unknown) {\n\treturn err instanceof Error && 'code' in err && err.code === 'ENOENT'\n}\n\n/**\n * Write a file by writing to a unique temporary file and renaming it into place, so concurrent\n * writers never observe a partial file. The temp file is cleaned up if the rename fails.\n */\nasync function writeFileAtomic(filePath: string, content: string) {\n\tconst tmp = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`\n\n\tawait fs.writeFile(tmp, content)\n\n\ttry {\n\t\tawait fs.rename(tmp, filePath)\n\t} catch (err) {\n\t\tawait fs.rm(tmp, { force: true })\n\t\tthrow err\n\t}\n}\n\n/**\n * Run a write task after all previously queued writes have settled. A rejection doesn't break the\n * chain for later tasks.\n */\nfunction enqueueWrite<T>(task: () => Promise<T>) {\n\t// wait for the previous write to finish, then run this one, even if the previous one failed\n\tconst run = writeChain.then(task, task)\n\n\t// move the queue on to this write, but turn either outcome into success so it never rejects\n\twriteChain = run.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t)\n\n\t// return the real promise, so the caller still sees this write's value or error\n\treturn run\n}\n\n/**\n * Write a file only if the content differs from what is already on disk, so watchers are not woken\n * by a needless mtime change.\n */\nexport async function maybeWrite(filePath: string, content: string) {\n\ttry {\n\t\tif ((await fs.readFile(filePath, 'utf-8')) === content) return false\n\t} catch (err) {\n\t\tif (!isENOENT(err)) throw err\n\t}\n\n\tawait writeFileAtomic(filePath, content)\n\n\treturn true\n}\n\n// matches `[css, classes, href] = cxx\\`...\\`` and `cxx.tag<T>('name')\\`...\\``\n// capture groups: 1 optional `export `, 2-4 assigned variable names, 5 plain\n// css body, 6 quote kind, 7 tag name, 8 tagged css body\nconst regex =\n\t/((?:export\\s+)?)(?:const|var|let)\\s*\\[(\\w*)\\s*,?\\s*(\\w*)\\s*,?\\s*(\\w*)\\s*\\]\\s*=\\s*cxx(?:\\s*`([\\s\\S]*?)`|\\s*\\.\\s*tag(?:\\s*<[^>]+>)?\\s*\\(\\s*(['\"])(.*?)\\6\\s*\\)\\s*`([\\s\\S]*?)`)/gm\n\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/\n\n/**\n * Hash transformed CSS into a stable href for style deduplication.\n */\nfunction hashCss(code: Uint8Array) {\n\treturn `cxx-${createHash('sha256').update(code).digest('base64url').slice(0, 12)}`\n}\n\nexport class DuplicateTagError extends Error {\n\tname = 'DuplicateTagError'\n\n\tconstructor(tag: string) {\n\t\tsuper(`Tag ${tag} has already been seen. Tags must be unique across your application`)\n\t}\n}\n\nexport class InvalidTagError extends Error {\n\tname = 'InvalidTagError'\n\n\tconstructor(tag: string) {\n\t\tsuper(\n\t\t\t`Tag \"${tag}\" does not map to a valid TypeScript identifier. ` +\n\t\t\t\t`Use letters, numbers, spaces, \"_\" or \"-\"`,\n\t\t)\n\t}\n}\n\n/**\n * Transform `cxx` templates in one source file and collect any exported tag types.\n */\nexport function collect(source: string, id: string, config: PluginConfig) {\n\tconst configKey = JSON.stringify(config)\n\n\t// reuse the last result when the source and config are unchanged\n\tconst cached = collectCache.get(id)\n\tif (cached?.source === source && cached.config === configKey) return cached\n\n\tconst tags: Tags = new Map()\n\tconst magic = new MagicString(source)\n\n\tlet matched = false\n\n\t// the regex is global, so reset its cursor before scanning\n\tregex.lastIndex = 0\n\n\tlet match: RegExpExecArray | null\n\n\t// walk every cxx template and replace it in place\n\twhile ((match = regex.exec(source))) {\n\t\tmatched = true\n\n\t\t// capture groups: export, three bindings, plain css, (quote), tag, tagged css\n\t\tconst [, exp, varOne, varTwo, varThree, plainCss, , tag, taggedCss] = match\n\t\tconst css = plainCss ?? taggedCss\n\t\tconst matchIndex = match.index\n\n\t\t// compile the CSS to minified CSS Modules, reporting the source line on failure\n\t\tconst { code, exports: classExports = {} } = (() => {\n\t\t\ttry {\n\t\t\t\treturn transform({\n\t\t\t\t\tminify: true,\n\t\t\t\t\tcssModules: true,\n\t\t\t\t\tfilename: id,\n\t\t\t\t\tcode: encoder.encode(css),\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconst line = source.slice(0, matchIndex).split('\\n').length\n\t\t\t\tthrow new Error(`Failed to compile cxx CSS at ${id}:${line}`, { cause: err })\n\t\t\t}\n\t\t})()\n\n\t\tconst href = hashCss(code)\n\t\t// map each class name to its generated (scoped) name\n\t\tconst styles = Object.fromEntries(\n\t\t\tObject.entries(classExports).map(([k, v]) => [k, v.name]),\n\t\t)\n\n\t\tif (tag) {\n\t\t\tconst suffix =\n\t\t\t\ttypeof config.typeSuffix === 'string'\n\t\t\t\t\t? config.typeSuffix\n\t\t\t\t\t: config.typeSuffix === false\n\t\t\t\t\t\t? ''\n\t\t\t\t\t\t: 'Classes'\n\t\t\tconst tagWithSuffix = pascalise(`${tag}${suffix}`)\n\n\t\t\tif (!IDENTIFIER.test(tagWithSuffix)) throw new InvalidTagError(tag)\n\t\t\tif (tags.has(tagWithSuffix)) throw new DuplicateTagError(tagWithSuffix)\n\n\t\t\t// side effect but necessary\n\t\t\ttags.set(tagWithSuffix, Object.keys(styles))\n\t\t}\n\n\t\tconst statements: string[] = []\n\n\t\tif (varOne) {\n\t\t\tstatements.push(`${exp}const ${varOne} = ${JSON.stringify(decoder.decode(code))}`)\n\t\t}\n\n\t\tif (varTwo) {\n\t\t\tstatements.push(`${exp}const ${varTwo} = ${JSON.stringify(styles)}`)\n\t\t}\n\n\t\tif (varThree) {\n\t\t\tstatements.push(`${exp}const ${varThree} = ${JSON.stringify(href)}`)\n\t\t}\n\n\t\t// swap the template for the generated declarations, keeping the export keyword\n\t\tmagic.overwrite(matchIndex, matchIndex + match[0].length, statements.join('\\n'))\n\t}\n\n\tconst template = magic.toString()\n\t// only build a map when something was actually rewritten\n\tconst map = matched\n\t\t? magic.generateMap({ source: id, includeContent: true, hires: true })\n\t\t: null\n\tconst result = { source, config: configKey, template, tags, map }\n\n\tcollectCache.set(id, result)\n\n\treturn result\n}\n\n/**\n * Render the generated declaration file contents for a set of collected tags.\n */\nfunction renderTypes(tags: Tags) {\n\treturn [\n\t\tAUTOGEN_MSG,\n\t\t'',\n\t\t`import '${PKG_NAME}'`,\n\t\t'',\n\t\t`declare module '${PKG_NAME}' {`,\n\t\ttagsToType(tags),\n\t\t'}',\n\t\t'',\n\t].join('\\n')\n}\n\n/**\n * Write (or remove) the generated `index.d.ts` for a full tag surface.\n */\nasync function writeRenderedTypes(tags: Tags) {\n\tconst filePath = path.join(GENERATED_DIR, 'index.d.ts')\n\n\tif (!tags.size) {\n\t\tawait fs.rm(filePath, { force: true })\n\t\treturn\n\t}\n\n\tawait fs.mkdir(GENERATED_DIR, { recursive: true })\n\tawait maybeWrite(filePath, renderTypes(tags))\n}\n\nconst PARTIAL_DIR = path.join(GENERATED_DIR, 'tags')\n\n// wait this long after the last file before rebuilding, so a burst of files\n// only re-reads the partials once\nconst REBUILD_WAIT = 100\n\nlet rebuildTimer: ReturnType<typeof setTimeout> | null = null\n\n/**\n * Map a source file to its partial file, named by a hash of the absolute path so each file has\n * exactly one partial.\n */\nfunction partialPath(filePath: string) {\n\treturn path.join(\n\t\tPARTIAL_DIR,\n\t\t`${createHash('sha1').update(filePath).digest('hex')}.json`,\n\t)\n}\n\ntype DuplicateTag = {\n\ttag: string\n\tfiles: string[]\n}\n\n/**\n * Read every per-file partial and merge them into one tag map. Partials whose source file no\n * longer exists are pruned, and duplicate tag names are reported with the files that define them.\n */\nasync function readPartials(): Promise<{ tags: Tags; duplicates: DuplicateTag[] }> {\n\tlet entries: string[]\n\n\ttry {\n\t\tentries = await fs.readdir(PARTIAL_DIR)\n\t} catch (err) {\n\t\tif (isENOENT(err)) return { tags: new Map(), duplicates: [] }\n\t\tthrow err\n\t}\n\n\tconst tags: Tags = new Map()\n\tconst fileByTag = new Map<string, string>()\n\tconst duplicates: DuplicateTag[] = []\n\n\tfor (const entry of entries) {\n\t\tif (!entry.endsWith('.json')) continue\n\n\t\tconst partial = path.join(PARTIAL_DIR, entry)\n\t\tlet parsed: { file: string; tags: Record<string, string[]> }\n\n\t\ttry {\n\t\t\tparsed = JSON.parse(await fs.readFile(partial, 'utf-8'))\n\t\t} catch {\n\t\t\tcontinue\n\t\t}\n\n\t\tlet source: string\n\n\t\ttry {\n\t\t\tsource = await fs.readFile(parsed.file, 'utf-8')\n\t\t} catch {\n\t\t\tawait fs.rm(partial, { force: true })\n\t\t\tcontinue\n\t\t}\n\n\t\t// drop partials for files that no longer use cxx, so their tags do not linger\n\t\tif (!source.includes('cxx')) {\n\t\t\tawait fs.rm(partial, { force: true })\n\t\t\tcontinue\n\t\t}\n\n\t\tfor (const [name, classes] of Object.entries(parsed.tags)) {\n\t\t\tconst existing = fileByTag.get(name)\n\n\t\t\tif (existing) {\n\t\t\t\tduplicates.push({ tag: name, files: [existing, parsed.file] })\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfileByTag.set(name, parsed.file)\n\t\t\ttags.set(name, classes)\n\t\t}\n\t}\n\n\treturn { tags, duplicates }\n}\n\n/**\n * Persist one file's tags to its own partial, then rebuild the shared types soon. Rebuilding is\n * debounced and serialised, so a large build does not re-read every partial per file.\n */\nexport function writeTypesForFile(filePath: string, tags: Tags) {\n\treturn enqueueWrite(async () => {\n\t\tawait fs.mkdir(PARTIAL_DIR, { recursive: true })\n\n\t\tconst partial = partialPath(filePath)\n\n\t\tif (!tags.size) {\n\t\t\tawait fs.rm(partial, { force: true })\n\t\t} else {\n\t\t\tawait writeFileAtomic(\n\t\t\t\tpartial,\n\t\t\t\tJSON.stringify({ file: filePath, tags: Object.fromEntries(tags) }),\n\t\t\t)\n\t\t}\n\t})\n\t\t.then(() => scheduleRebuild())\n\t\t.catch(err => {\n\t\t\tlogger.error(`failed to write types for ${filePath}`, err)\n\t\t})\n}\n\n/**\n * Queue a rebuild of `index.d.ts` after a short delay, so a burst of writes only rebuilds once.\n */\nfunction scheduleRebuild() {\n\tif (rebuildTimer) clearTimeout(rebuildTimer)\n\n\trebuildTimer = setTimeout(() => {\n\t\trebuildTimer = null\n\t\tflushTypes().catch(err => {\n\t\t\tlogger.error('failed to generate types', err)\n\t\t})\n\t}, REBUILD_WAIT)\n}\n\n/**\n * Rebuild `index.d.ts` from every partial.\n */\nexport function flushTypes() {\n\tif (rebuildTimer) {\n\t\tclearTimeout(rebuildTimer)\n\t\trebuildTimer = null\n\t}\n\n\treturn enqueueWrite(async () => {\n\t\tconst { tags, duplicates } = await readPartials()\n\t\tawait writeRenderedTypes(tags)\n\n\t\tfor (const duplicate of duplicates) {\n\t\t\tlogger.error(\n\t\t\t\t`Tag \"${duplicate.tag}\" is defined in multiple files: ${duplicate.files.join(', ')}`,\n\t\t\t)\n\t\t}\n\t})\n}\n\nexport const SOURCE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx'])\n\n// directories that never contain source we transform\nconst SKIP_DIRS = new Set(['node_modules', 'dist', 'build', 'coverage', 'out'])\n\n/**\n * Run `fn` for every item, with at most `concurrency` calls in flight.\n */\nasync function runWithConcurrency<T>(\n\titems: T[],\n\tconcurrency: number,\n\tfn: (item: T) => Promise<void>,\n) {\n\tlet cursor = 0\n\n\tconst workers = Array.from(\n\t\t{ length: Math.min(concurrency, items.length) },\n\t\tasync () => {\n\t\t\twhile (cursor < items.length) {\n\t\t\t\tconst index = cursor++\n\t\t\t\tawait fn(items[index])\n\t\t\t}\n\t\t},\n\t)\n\n\tawait Promise.all(workers)\n}\n\n/**\n * Read one file, collect its tags, and persist them. A file with no `cxx` usage has its partial\n * removed, so stale tags drop out.\n */\nexport async function refreshFile(file: string, config: PluginConfig) {\n\tlet source: string\n\n\ttry {\n\t\tsource = await fs.readFile(file, 'utf-8')\n\t} catch (err) {\n\t\tif (!isENOENT(err)) throw err\n\t\tawait writeTypesForFile(file, new Map())\n\t\treturn\n\t}\n\n\tconst tags = source.includes('cxx') ? collect(source, file, config).tags : new Map()\n\tawait writeTypesForFile(file, tags)\n}\n\n/**\n * Walk every source file under `root` and seed the type surface, so a fresh checkout (and a build\n * with no edits) has types without waiting for a transform.\n */\nexport async function seedTypes(root: string, config: PluginConfig) {\n\tasync function scan(dir: string) {\n\t\tlet entries: Dirent[]\n\n\t\ttry {\n\t\t\tentries = await fs.readdir(dir, { withFileTypes: true })\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\n\t\tawait runWithConcurrency(entries, 8, async entry => {\n\t\t\tif (entry.name.startsWith('.') || SKIP_DIRS.has(entry.name)) return\n\n\t\t\tconst full = path.join(dir, entry.name)\n\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tawait scan(full)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (!SOURCE_EXTENSIONS.has(path.extname(entry.name))) return\n\n\t\t\tawait refreshFile(full, config)\n\t\t})\n\t}\n\n\tawait scan(root)\n\tawait flushTypes()\n}\n\n/**\n * Render collected tags as a module augmentation for the package entrypoint.\n */\nexport function tagsToType(tags: Tags) {\n\treturn [...tags]\n\t\t.toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t.map(([tag, classes]) => {\n\t\t\tconst union =\n\t\t\t\tclasses.length > 0\n\t\t\t\t\t? classes\n\t\t\t\t\t\t\t.toSorted((a, b) => a.length - b.length)\n\t\t\t\t\t\t\t.map(c => `'${c}'`)\n\t\t\t\t\t\t\t.join(' | ')\n\t\t\t\t\t: 'never'\n\n\t\t\treturn `\\texport type ${tag} = ${union}`\n\t\t})\n\t\t.join('\\n')\n}\n",
|
|
6
6
|
"export const NAME = 'cxx'\nexport const PKG_NAME = `@jk2908/${NAME}`\nexport const GENERATED_DIR = `.${NAME}`\nexport const AUTOGEN_MSG = `// auto-generated by ${NAME}`\n",
|
|
7
|
+
"const LEVELS = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n\tfatal: 4,\n} as const\n\nexport type LogLevel = keyof typeof LEVELS\n\nconst defaultLevel: LogLevel = process.env['NODE_ENV'] === 'production' ? 'error' : 'info'\n\ntype LogEntry = {\n\tts: number\n\tlevel: LogLevel\n\tmessage: string\n\terror?:\n\t\t| Error\n\t\t| {\n\t\t\t\tmessage: string\n\t\t\t\tstack?: string\n\t\t\t\tcause?: unknown\n\t\t }\n}\n\n/**\n * Log messages with different severity levels.\n */\nexport class Logger {\n\t#level: LogLevel = defaultLevel\n\n\tconstructor(public name?: string) {}\n\n\t/**\n\t * Convert a value to an Error instance.\n\t */\n\tstatic toError(err: unknown) {\n\t\treturn err instanceof Error ? err : new Error(String(err), { cause: err })\n\t}\n\n\t/**\n\t * Stringify the error for logging.\n\t */\n\tstatic print(err: unknown) {\n\t\tif (err instanceof Error) {\n\t\t\treturn err.message + (err.stack ? `\\n${err.stack}` : '')\n\t\t}\n\n\t\t// for plain objects, attempt to stringify with indentation\n\t\t// for readability\n\t\tif (typeof err === 'object' && err !== null) {\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(err, null, 2)\n\t\t\t} catch {\n\t\t\t\t// if stringify fails (e.g. circular reference), fall back\n\t\t\t\t// to basic string conversion\n\t\t\t\treturn String(err)\n\t\t\t}\n\t\t}\n\n\t\treturn String(err)\n\t}\n\n\tset level(level: LogLevel) {\n\t\tthis.#level = level\n\t}\n\n\tget level() {\n\t\treturn this.#level\n\t}\n\n\t/**\n\t * Log a message with a specific level.\n\t */\n\tlog(level: LogLevel, message: string, error?: Error) {\n\t\tif (LEVELS[level] < LEVELS[this.level]) return\n\n\t\tconst entry: LogEntry = {\n\t\t\tts: Date.now(),\n\t\t\tlevel,\n\t\t\tmessage,\n\t\t}\n\n\t\tif (level === 'error' || level === 'fatal') {\n\t\t\tentry.error = error ? Logger.toError(error) : new Error(message)\n\t\t}\n\n\t\tconst line = `${this.name ? `[${this.name}]` : ''} [${entry.ts}] [${level.toUpperCase()}] ${message}`\n\t\tconst extra = entry.error ? `\\n${Logger.print(entry.error)}` : ''\n\n\t\tif (level === 'warn') {\n\t\t\tconsole.warn(line, extra)\n\t\t\treturn\n\t\t}\n\n\t\tif (level === 'error' || level === 'fatal') {\n\t\t\tconsole.error(line, extra)\n\t\t\treturn\n\t\t}\n\n\t\tconsole.log(line, extra)\n\t}\n\n\t/**\n\t * Log a debug message.\n\t */\n\tdebug(...messages: string[]) {\n\t\tthis.log('debug', messages.join(' '))\n\t}\n\n\t/**\n\t * Log an info message.\n\t */\n\tinfo(...messages: string[]) {\n\t\tthis.log('info', messages.join(' '))\n\t}\n\n\t/**\n\t * Log a warning message.\n\t */\n\twarn(...messages: string[]) {\n\t\tthis.log('warn', messages.join(' '))\n\t}\n\n\t/**\n\t * Log an error message.\n\t */\n\terror(message: string, error?: unknown) {\n\t\tthis.log('error', message, error === undefined ? undefined : Logger.toError(error))\n\t}\n\n\t/**\n\t * Log a fatal error message.\n\t */\n\tfatal(message: string, error?: unknown) {\n\t\tthis.log('fatal', message, error === undefined ? undefined : Logger.toError(error))\n\t}\n}\n",
|
|
7
8
|
"export const CACHE_MAX_SIZE = 100\n\nexport class LruCache<T> {\n\t#cache: Map<string, T> = new Map()\n\t#maxSize: number\n\n\tconstructor(maxSize = CACHE_MAX_SIZE) {\n\t\tthis.#maxSize = maxSize\n\t}\n\n\tget size() {\n\t\treturn this.#cache.size\n\t}\n\n\t/**\n\t * Retrieve a cached value and promote it to most-recently-used so it won't\n\t * be evicted while still actively referenced.\n\t */\n\tget(key: string) {\n\t\tconst cached = this.#cache.get(key)\n\t\tif (this.#cache.has(key)) this.set(key, cached as T)\n\n\t\treturn cached\n\t}\n\n\t/**\n\t * Promote an existing cache entry to most-recently-used by deleting and\n\t * re-inserting it, which moves it to the end of the Map's iteration\n\t * order. If the cache is at capacity, evict the least recently used\n\t * entry (front) before inserting.\n\t */\n\tset(key: string, value: T) {\n\t\t// drop any existing entry\n\t\tthis.#cache.delete(key)\n\n\t\tif (this.#cache.size >= this.#maxSize) {\n\t\t\tconst lru = this.#cache.keys().next().value\n\t\t\tif (lru !== undefined) this.#cache.delete(lru)\n\t\t}\n\n\t\tthis.#cache.set(key, value)\n\t}\n\n\tdelete(key: string) {\n\t\treturn this.#cache.delete(key)\n\t}\n\n\tclear() {\n\t\treturn this.#cache.clear()\n\t}\n}\n",
|
|
8
|
-
"export function capitalise(str: string) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function pascalise(str: string) {\n\treturn str\n\t\t.split(/[ _-]+/)\n\t\t.map(capitalise)\n\t\t.join('')\n}\n
|
|
9
|
-
"import { realpathSync } from 'node:fs'\nimport
|
|
10
|
-
"const LEVELS = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n\tfatal: 4,\n} as const\n\nexport type LogLevel = keyof typeof LEVELS\n\nconst defaultLevel: LogLevel = process.env['NODE_ENV'] === 'production' ? 'error' : 'info'\n\ntype LogEntry = {\n\tts: number\n\tlevel: LogLevel\n\tmessage: string\n\terror?:\n\t\t| Error\n\t\t| {\n\t\t\t\tmessage: string\n\t\t\t\tstack?: string\n\t\t\t\tcause?: unknown\n\t\t }\n}\n\n/**\n * Log messages with different severity levels.\n */\nexport class Logger {\n\t#level: LogLevel\n\n\tconstructor(\n\t\tlevel?: LogLevel,\n\t\tpublic name?: string,\n\t) {\n\t\tthis.#level = level ?? defaultLevel\n\t}\n\n\t/**\n\t * Convert a value to an Error instance.\n\t */\n\tstatic toError(err: unknown) {\n\t\treturn err instanceof Error ? err : new Error(String(err), { cause: err })\n\t}\n\n\t/**\n\t * Stringify the error for logging.\n\t */\n\tstatic print(err: unknown) {\n\t\tif (err instanceof Error) {\n\t\t\treturn err.message + (err.stack ? `\\n${err.stack}` : '')\n\t\t}\n\n\t\t// for plain objects, attempt to stringify with indentation\n\t\t// for readability\n\t\tif (typeof err === 'object' && err !== null) {\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(err, null, 2)\n\t\t\t} catch {\n\t\t\t\t// if stringify fails (e.g. circular reference), fall back\n\t\t\t\t// to basic string conversion\n\t\t\t\treturn String(err)\n\t\t\t}\n\t\t}\n\n\t\treturn String(err)\n\t}\n\n\tset level(level: LogLevel) {\n\t\tthis.#level = level\n\t}\n\n\tget level() {\n\t\treturn this.#level\n\t}\n\n\t/**\n\t * Log a message with a specific level.\n\t */\n\tlog(level: LogLevel, message: string, error?: Error) {\n\t\tif (LEVELS[level] < LEVELS[this.level]) return\n\n\t\tconst entry: LogEntry = {\n\t\t\tts: Date.now(),\n\t\t\tlevel,\n\t\t\tmessage,\n\t\t}\n\n\t\tif (level === 'error' || level === 'fatal') {\n\t\t\tentry.error = error ? Logger.toError(error) : new Error(message)\n\t\t}\n\n\t\tconst line = `${this.name ? `[${this.name}]` : ''} [${entry.ts}] [${level.toUpperCase()}] ${message}`\n\t\tconst extra = entry.error ? `\\n${Logger.print(entry.error)}` : ''\n\n\t\tif (level === 'warn') {\n\t\t\tconsole.warn(line, extra)\n\t\t\treturn\n\t\t}\n\n\t\tif (level === 'error' || level === 'fatal') {\n\t\t\tconsole.error(line, extra)\n\t\t\treturn\n\t\t}\n\n\t\tconsole.log(line, extra)\n\t}\n\n\t/**\n\t * Log a debug message.\n\t */\n\tdebug(...messages: string[]) {\n\t\tthis.log('debug', messages.join(' '))\n\t}\n\n\t/**\n\t * Log an info message.\n\t */\n\tinfo(...messages: string[]) {\n\t\tthis.log('info', messages.join(' '))\n\t}\n\n\t/**\n\t * Log a warning message.\n\t */\n\twarn(...messages: string[]) {\n\t\tthis.log('warn', messages.join(' '))\n\t}\n\n\t/**\n\t * Log an error message.\n\t */\n\terror(message: string, error?: unknown) {\n\t\tthis.log('error', message, error === undefined ? undefined : Logger.toError(error))\n\t}\n\n\t/**\n\t * Log a fatal error message.\n\t */\n\tfatal(message: string, error?: unknown) {\n\t\tthis.log('fatal', message, error === undefined ? undefined : Logger.toError(error))\n\t}\n}\n"
|
|
9
|
+
"export function capitalise(str: string) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function pascalise(str: string) {\n\treturn str\n\t\t.split(/[ _-]+/)\n\t\t.map(capitalise)\n\t\t.join('')\n}\n",
|
|
10
|
+
"import { realpathSync } from 'node:fs'\nimport path from 'node:path'\n\nimport { type Plugin, type ResolvedConfig, type ViteDevServer } from 'vite'\n\nimport type { PluginConfig } from '../types.js'\nimport {\n\tcollect,\n\tflushTypes,\n\trefreshFile,\n\tseedTypes,\n\tSOURCE_EXTENSIONS,\n\twriteTypesForFile,\n} from '../build.js'\nimport { GENERATED_DIR } from '../config.js'\nimport { Logger } from '../logger.js'\n\ntype WatchEvent = 'add' | 'change' | 'unlink'\n\nfunction normaliseWatchPath(p: string) {\n\treturn p.replace(/\\\\/g, '/')\n}\n\nexport default function cxx(pluginConfig: PluginConfig = {}) {\n\tconst logger = new Logger()\n\n\t// resolved from Vite's root in `configResolved`, not from `process.cwd()`\n\tlet watchRoot = normaliseWatchPath(process.cwd())\n\tlet seeded = false\n\n\t// realpath is synchronous, so cache it per directory to keep it off the transform hot path\n\tconst realpaths = new Map<string, string>()\n\n\tfunction resolveWatchFile(filePath: string) {\n\t\tconst absolutePath = path.resolve(watchRoot, filePath)\n\t\tconst parentPath = path.dirname(absolutePath)\n\n\t\tlet resolvedParentPath = realpaths.get(parentPath)\n\n\t\tif (resolvedParentPath === undefined) {\n\t\t\ttry {\n\t\t\t\tresolvedParentPath = normaliseWatchPath(realpathSync.native(parentPath))\n\t\t\t} catch {\n\t\t\t\tresolvedParentPath = normaliseWatchPath(parentPath)\n\t\t\t}\n\n\t\t\trealpaths.set(parentPath, resolvedParentPath)\n\t\t}\n\n\t\treturn normaliseWatchPath(path.join(resolvedParentPath, path.basename(absolutePath)))\n\t}\n\n\t/**\n\t * Returns the canonical, watchable path, or null when the file is irrelevant.\n\t */\n\tfunction watchedFile(filePath: string) {\n\t\tconst resolvedPath = resolveWatchFile(filePath)\n\n\t\tif (\n\t\t\tresolvedPath.startsWith(`${watchRoot}/`) &&\n\t\t\t!resolvedPath.includes(`/${GENERATED_DIR}/`) &&\n\t\t\tSOURCE_EXTENSIONS.has(path.extname(resolvedPath))\n\t\t) {\n\t\t\treturn resolvedPath\n\t\t}\n\n\t\treturn null\n\t}\n\n\tasync function handleEvent(event: WatchEvent, file: string) {\n\t\tif (event === 'unlink') {\n\t\t\tawait writeTypesForFile(file, new Map())\n\t\t} else {\n\t\t\tawait refreshFile(file, pluginConfig)\n\t\t}\n\n\t\tlogger.info(`updated types from ${file}`)\n\t}\n\n\tfunction onWatch(event: WatchEvent) {\n\t\treturn (p: string) => {\n\t\t\tconst file = watchedFile(p)\n\t\t\tif (!file) return\n\n\t\t\tvoid handleEvent(event, file).catch(err => {\n\t\t\t\tlogger.error(`failed to update types from ${file}`, err)\n\t\t\t})\n\t\t}\n\t}\n\n\tasync function seed() {\n\t\tif (seeded) return\n\t\tseeded = true\n\n\t\tawait seedTypes(watchRoot, pluginConfig)\n\t}\n\n\treturn {\n\t\tname: 'cxx',\n\t\tenforce: 'pre',\n\t\tconfigResolved(config: ResolvedConfig) {\n\t\t\tconst root = pluginConfig.watch?.root ?? config.root\n\n\t\t\ttry {\n\t\t\t\twatchRoot = normaliseWatchPath(realpathSync.native(root))\n\t\t\t} catch {\n\t\t\t\twatchRoot = normaliseWatchPath(root)\n\t\t\t}\n\n\t\t\trealpaths.clear()\n\t\t},\n\t\tasync buildStart() {\n\t\t\tawait seed()\n\t\t},\n\t\ttransform(code, id) {\n\t\t\tif (id.startsWith('\\0') || id.includes('/node_modules/')) return null\n\t\t\t// cheap bail-out before running the regex/lightningcss on every module\n\t\t\tif (!code.includes('cxx')) return null\n\n\t\t\tconst cleanId = id.split('?')[0]\n\n\t\t\tif (!SOURCE_EXTENSIONS.has(path.extname(cleanId))) return null\n\n\t\t\tconst { template, tags, map } = collect(code, cleanId, pluginConfig)\n\n\t\t\tif (template === code) return null\n\n\t\t\tvoid writeTypesForFile(resolveWatchFile(cleanId), tags)\n\n\t\t\treturn {\n\t\t\t\tcode: template,\n\t\t\t\tmap,\n\t\t\t}\n\t\t},\n\t\tconfigureServer(server: ViteDevServer) {\n\t\t\tlogger.info('Watching for changes...')\n\n\t\t\tserver.watcher\n\t\t\t\t.on('add', onWatch('add'))\n\t\t\t\t.on('change', onWatch('change'))\n\t\t\t\t.on('unlink', onWatch('unlink'))\n\t\t},\n\t\tasync writeBundle() {\n\t\t\tawait flushTypes()\n\t\t},\n\t} satisfies Plugin\n}\n"
|
|
11
11
|
],
|
|
12
|
-
"mappings": "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",
|
|
13
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "294541A31A244C8364756E2164756E21",
|
|
14
14
|
"names": []
|
|
15
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jk2908/cxx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Utilities for generating styles in React 19",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
@@ -50,17 +50,17 @@
|
|
|
50
50
|
"prepack": "npm run build",
|
|
51
51
|
"test": "bunx vitest"
|
|
52
52
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"lightningcss": "^1.27.0",
|
|
55
|
+
"magic-string": "^0.30.21"
|
|
56
|
+
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/bun": "^1.3.13",
|
|
59
59
|
"@types/node": "^24.0.1",
|
|
60
60
|
"@types/react": "^19.2.17",
|
|
61
61
|
"@types/react-dom": "^19.2.3",
|
|
62
62
|
"@typescript/native-preview": "^7.0.0-dev.20260421.2",
|
|
63
|
-
|
|
63
|
+
"next": "^16.3.7",
|
|
64
64
|
"react": "^19.2.7",
|
|
65
65
|
"react-dom": "^19.2.7",
|
|
66
66
|
"typescript": "^5.5.4",
|
package/src/build.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Dirent } from 'node:fs'
|
|
2
|
+
|
|
1
3
|
import { createHash } from 'node:crypto'
|
|
2
4
|
import fs from 'node:fs/promises'
|
|
3
5
|
import path from 'node:path'
|
|
@@ -5,14 +7,16 @@ import path from 'node:path'
|
|
|
5
7
|
import { transform } from 'lightningcss'
|
|
6
8
|
import MagicString, { type SourceMap } from 'magic-string'
|
|
7
9
|
|
|
8
|
-
import type {
|
|
9
|
-
import { AUTOGEN_MSG, GENERATED_DIR, PKG_NAME } from './config.js'
|
|
10
|
+
import type { PluginConfig, Tags } from './types.js'
|
|
11
|
+
import { AUTOGEN_MSG, GENERATED_DIR, NAME, PKG_NAME } from './config.js'
|
|
12
|
+
import { Logger } from './logger.js'
|
|
10
13
|
import { LruCache } from './lru.js'
|
|
11
14
|
import { pascalise } from './utils.js'
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
const logger = new Logger(NAME)
|
|
17
|
+
|
|
15
18
|
const decoder = new TextDecoder()
|
|
19
|
+
const encoder = new TextEncoder()
|
|
16
20
|
|
|
17
21
|
/**
|
|
18
22
|
* LRU cache of `collect` results by file id + last seen source + config so watcher and transform
|
|
@@ -27,14 +31,8 @@ const collectCache = new LruCache<{
|
|
|
27
31
|
}>()
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*/
|
|
33
|
-
const fileCache = new LruCache<string>()
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Serialises type file writes inside a single process so overlapping `writeTypes` calls can't
|
|
37
|
-
* interleave or land out of order.
|
|
34
|
+
* Serialises type file writes inside a single process so overlapping writes can't interleave or
|
|
35
|
+
* land out of order.
|
|
38
36
|
*/
|
|
39
37
|
let writeChain: Promise<void> = Promise.resolve()
|
|
40
38
|
|
|
@@ -46,14 +44,20 @@ export function isENOENT(err: unknown) {
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
/**
|
|
49
|
-
* Write a file by
|
|
50
|
-
*
|
|
47
|
+
* Write a file by writing to a unique temporary file and renaming it into place, so concurrent
|
|
48
|
+
* writers never observe a partial file. The temp file is cleaned up if the rename fails.
|
|
51
49
|
*/
|
|
52
50
|
async function writeFileAtomic(filePath: string, content: string) {
|
|
53
51
|
const tmp = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`
|
|
54
52
|
|
|
55
53
|
await fs.writeFile(tmp, content)
|
|
56
|
-
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await fs.rename(tmp, filePath)
|
|
57
|
+
} catch (err) {
|
|
58
|
+
await fs.rm(tmp, { force: true })
|
|
59
|
+
throw err
|
|
60
|
+
}
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
/**
|
|
@@ -75,26 +79,17 @@ function enqueueWrite<T>(task: () => Promise<T>) {
|
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
/**
|
|
78
|
-
* Write a file only if the content
|
|
82
|
+
* Write a file only if the content differs from what is already on disk, so watchers are not woken
|
|
83
|
+
* by a needless mtime change.
|
|
79
84
|
*/
|
|
80
85
|
export async function maybeWrite(filePath: string, content: string) {
|
|
81
|
-
const cached = fileCache.get(filePath)
|
|
82
|
-
// fast path: already wrote this exact content in this process
|
|
83
|
-
if (cached === content) return false
|
|
84
|
-
|
|
85
|
-
// verify against disk on a cold start (or when the cache is stale) so we
|
|
86
|
-
// don't needlessly bump the mtime and invalidate downstream watchers
|
|
87
86
|
try {
|
|
88
|
-
if ((await fs.readFile(filePath, 'utf-8')) === content)
|
|
89
|
-
fileCache.set(filePath, content)
|
|
90
|
-
return false
|
|
91
|
-
}
|
|
87
|
+
if ((await fs.readFile(filePath, 'utf-8')) === content) return false
|
|
92
88
|
} catch (err) {
|
|
93
89
|
if (!isENOENT(err)) throw err
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
await writeFileAtomic(filePath, content)
|
|
97
|
-
fileCache.set(filePath, content)
|
|
98
93
|
|
|
99
94
|
return true
|
|
100
95
|
}
|
|
@@ -145,6 +140,7 @@ export function collect(source: string, id: string, config: PluginConfig) {
|
|
|
145
140
|
|
|
146
141
|
const tags: Tags = new Map()
|
|
147
142
|
const magic = new MagicString(source)
|
|
143
|
+
|
|
148
144
|
let matched = false
|
|
149
145
|
|
|
150
146
|
// the regex is global, so reset its cursor before scanning
|
|
@@ -159,19 +155,27 @@ export function collect(source: string, id: string, config: PluginConfig) {
|
|
|
159
155
|
// capture groups: export, three bindings, plain css, (quote), tag, tagged css
|
|
160
156
|
const [, exp, varOne, varTwo, varThree, plainCss, , tag, taggedCss] = match
|
|
161
157
|
const css = plainCss ?? taggedCss
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
158
|
+
const matchIndex = match.index
|
|
159
|
+
|
|
160
|
+
// compile the CSS to minified CSS Modules, reporting the source line on failure
|
|
161
|
+
const { code, exports: classExports = {} } = (() => {
|
|
162
|
+
try {
|
|
163
|
+
return transform({
|
|
164
|
+
minify: true,
|
|
165
|
+
cssModules: true,
|
|
166
|
+
filename: id,
|
|
167
|
+
code: encoder.encode(css),
|
|
168
|
+
})
|
|
169
|
+
} catch (err) {
|
|
170
|
+
const line = source.slice(0, matchIndex).split('\n').length
|
|
171
|
+
throw new Error(`Failed to compile cxx CSS at ${id}:${line}`, { cause: err })
|
|
172
|
+
}
|
|
173
|
+
})()
|
|
170
174
|
|
|
171
175
|
const href = hashCss(code)
|
|
172
176
|
// map each class name to its generated (scoped) name
|
|
173
177
|
const styles = Object.fromEntries(
|
|
174
|
-
Object.entries(
|
|
178
|
+
Object.entries(classExports).map(([k, v]) => [k, v.name]),
|
|
175
179
|
)
|
|
176
180
|
|
|
177
181
|
if (tag) {
|
|
@@ -205,7 +209,7 @@ export function collect(source: string, id: string, config: PluginConfig) {
|
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
// swap the template for the generated declarations, keeping the export keyword
|
|
208
|
-
magic.overwrite(
|
|
212
|
+
magic.overwrite(matchIndex, matchIndex + match[0].length, statements.join('\n'))
|
|
209
213
|
}
|
|
210
214
|
|
|
211
215
|
const template = magic.toString()
|
|
@@ -243,10 +247,7 @@ async function writeRenderedTypes(tags: Tags) {
|
|
|
243
247
|
const filePath = path.join(GENERATED_DIR, 'index.d.ts')
|
|
244
248
|
|
|
245
249
|
if (!tags.size) {
|
|
246
|
-
// `force` makes this a no-op when the file is already absent
|
|
247
250
|
await fs.rm(filePath, { force: true })
|
|
248
|
-
fileCache.delete(filePath)
|
|
249
|
-
|
|
250
251
|
return
|
|
251
252
|
}
|
|
252
253
|
|
|
@@ -254,15 +255,18 @@ async function writeRenderedTypes(tags: Tags) {
|
|
|
254
255
|
await maybeWrite(filePath, renderTypes(tags))
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
/**
|
|
258
|
-
* Write the generated declaration file for the current set of collected tags.
|
|
259
|
-
*/
|
|
260
|
-
export function writeTypes(tags: Tags) {
|
|
261
|
-
return enqueueWrite(() => writeRenderedTypes(tags))
|
|
262
|
-
}
|
|
263
|
-
|
|
264
258
|
const PARTIAL_DIR = path.join(GENERATED_DIR, 'tags')
|
|
265
259
|
|
|
260
|
+
// wait this long after the last file before rebuilding, so a burst of files
|
|
261
|
+
// only re-reads the partials once
|
|
262
|
+
const REBUILD_WAIT = 100
|
|
263
|
+
|
|
264
|
+
let rebuildTimer: ReturnType<typeof setTimeout> | null = null
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Map a source file to its partial file, named by a hash of the absolute path so each file has
|
|
268
|
+
* exactly one partial.
|
|
269
|
+
*/
|
|
266
270
|
function partialPath(filePath: string) {
|
|
267
271
|
return path.join(
|
|
268
272
|
PARTIAL_DIR,
|
|
@@ -270,21 +274,28 @@ function partialPath(filePath: string) {
|
|
|
270
274
|
)
|
|
271
275
|
}
|
|
272
276
|
|
|
277
|
+
type DuplicateTag = {
|
|
278
|
+
tag: string
|
|
279
|
+
files: string[]
|
|
280
|
+
}
|
|
281
|
+
|
|
273
282
|
/**
|
|
274
|
-
* Read every per-file partial
|
|
275
|
-
*
|
|
283
|
+
* Read every per-file partial and merge them into one tag map. Partials whose source file no
|
|
284
|
+
* longer exists are pruned, and duplicate tag names are reported with the files that define them.
|
|
276
285
|
*/
|
|
277
|
-
async function readPartials() {
|
|
286
|
+
async function readPartials(): Promise<{ tags: Tags; duplicates: DuplicateTag[] }> {
|
|
278
287
|
let entries: string[]
|
|
279
288
|
|
|
280
289
|
try {
|
|
281
290
|
entries = await fs.readdir(PARTIAL_DIR)
|
|
282
291
|
} catch (err) {
|
|
283
|
-
if (isENOENT(err)) return new Map()
|
|
292
|
+
if (isENOENT(err)) return { tags: new Map(), duplicates: [] }
|
|
284
293
|
throw err
|
|
285
294
|
}
|
|
286
295
|
|
|
287
296
|
const tags: Tags = new Map()
|
|
297
|
+
const fileByTag = new Map<string, string>()
|
|
298
|
+
const duplicates: DuplicateTag[] = []
|
|
288
299
|
|
|
289
300
|
for (const entry of entries) {
|
|
290
301
|
if (!entry.endsWith('.json')) continue
|
|
@@ -298,25 +309,40 @@ async function readPartials() {
|
|
|
298
309
|
continue
|
|
299
310
|
}
|
|
300
311
|
|
|
312
|
+
let source: string
|
|
313
|
+
|
|
301
314
|
try {
|
|
302
|
-
await fs.
|
|
315
|
+
source = await fs.readFile(parsed.file, 'utf-8')
|
|
303
316
|
} catch {
|
|
304
317
|
await fs.rm(partial, { force: true })
|
|
305
318
|
continue
|
|
306
319
|
}
|
|
307
320
|
|
|
321
|
+
// drop partials for files that no longer use cxx, so their tags do not linger
|
|
322
|
+
if (!source.includes('cxx')) {
|
|
323
|
+
await fs.rm(partial, { force: true })
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
326
|
+
|
|
308
327
|
for (const [name, classes] of Object.entries(parsed.tags)) {
|
|
309
|
-
|
|
328
|
+
const existing = fileByTag.get(name)
|
|
329
|
+
|
|
330
|
+
if (existing) {
|
|
331
|
+
duplicates.push({ tag: name, files: [existing, parsed.file] })
|
|
332
|
+
continue
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
fileByTag.set(name, parsed.file)
|
|
310
336
|
tags.set(name, classes)
|
|
311
337
|
}
|
|
312
338
|
}
|
|
313
339
|
|
|
314
|
-
return tags
|
|
340
|
+
return { tags, duplicates }
|
|
315
341
|
}
|
|
316
342
|
|
|
317
343
|
/**
|
|
318
|
-
*
|
|
319
|
-
*
|
|
344
|
+
* Persist one file's tags to its own partial, then rebuild the shared types soon. Rebuilding is
|
|
345
|
+
* debounced and serialised, so a large build does not re-read every partial per file.
|
|
320
346
|
*/
|
|
321
347
|
export function writeTypesForFile(filePath: string, tags: Tags) {
|
|
322
348
|
return enqueueWrite(async () => {
|
|
@@ -332,16 +358,135 @@ export function writeTypesForFile(filePath: string, tags: Tags) {
|
|
|
332
358
|
JSON.stringify({ file: filePath, tags: Object.fromEntries(tags) }),
|
|
333
359
|
)
|
|
334
360
|
}
|
|
361
|
+
})
|
|
362
|
+
.then(() => scheduleRebuild())
|
|
363
|
+
.catch(err => {
|
|
364
|
+
logger.error(`failed to write types for ${filePath}`, err)
|
|
365
|
+
})
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Queue a rebuild of `index.d.ts` after a short delay, so a burst of writes only rebuilds once.
|
|
370
|
+
*/
|
|
371
|
+
function scheduleRebuild() {
|
|
372
|
+
if (rebuildTimer) clearTimeout(rebuildTimer)
|
|
373
|
+
|
|
374
|
+
rebuildTimer = setTimeout(() => {
|
|
375
|
+
rebuildTimer = null
|
|
376
|
+
flushTypes().catch(err => {
|
|
377
|
+
logger.error('failed to generate types', err)
|
|
378
|
+
})
|
|
379
|
+
}, REBUILD_WAIT)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Rebuild `index.d.ts` from every partial.
|
|
384
|
+
*/
|
|
385
|
+
export function flushTypes() {
|
|
386
|
+
if (rebuildTimer) {
|
|
387
|
+
clearTimeout(rebuildTimer)
|
|
388
|
+
rebuildTimer = null
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return enqueueWrite(async () => {
|
|
392
|
+
const { tags, duplicates } = await readPartials()
|
|
393
|
+
await writeRenderedTypes(tags)
|
|
335
394
|
|
|
336
|
-
|
|
395
|
+
for (const duplicate of duplicates) {
|
|
396
|
+
logger.error(
|
|
397
|
+
`Tag "${duplicate.tag}" is defined in multiple files: ${duplicate.files.join(', ')}`,
|
|
398
|
+
)
|
|
399
|
+
}
|
|
337
400
|
})
|
|
338
401
|
}
|
|
339
402
|
|
|
403
|
+
export const SOURCE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx'])
|
|
404
|
+
|
|
405
|
+
// directories that never contain source we transform
|
|
406
|
+
const SKIP_DIRS = new Set(['node_modules', 'dist', 'build', 'coverage', 'out'])
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Run `fn` for every item, with at most `concurrency` calls in flight.
|
|
410
|
+
*/
|
|
411
|
+
async function runWithConcurrency<T>(
|
|
412
|
+
items: T[],
|
|
413
|
+
concurrency: number,
|
|
414
|
+
fn: (item: T) => Promise<void>,
|
|
415
|
+
) {
|
|
416
|
+
let cursor = 0
|
|
417
|
+
|
|
418
|
+
const workers = Array.from(
|
|
419
|
+
{ length: Math.min(concurrency, items.length) },
|
|
420
|
+
async () => {
|
|
421
|
+
while (cursor < items.length) {
|
|
422
|
+
const index = cursor++
|
|
423
|
+
await fn(items[index])
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
await Promise.all(workers)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Read one file, collect its tags, and persist them. A file with no `cxx` usage has its partial
|
|
433
|
+
* removed, so stale tags drop out.
|
|
434
|
+
*/
|
|
435
|
+
export async function refreshFile(file: string, config: PluginConfig) {
|
|
436
|
+
let source: string
|
|
437
|
+
|
|
438
|
+
try {
|
|
439
|
+
source = await fs.readFile(file, 'utf-8')
|
|
440
|
+
} catch (err) {
|
|
441
|
+
if (!isENOENT(err)) throw err
|
|
442
|
+
await writeTypesForFile(file, new Map())
|
|
443
|
+
return
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const tags = source.includes('cxx') ? collect(source, file, config).tags : new Map()
|
|
447
|
+
await writeTypesForFile(file, tags)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Walk every source file under `root` and seed the type surface, so a fresh checkout (and a build
|
|
452
|
+
* with no edits) has types without waiting for a transform.
|
|
453
|
+
*/
|
|
454
|
+
export async function seedTypes(root: string, config: PluginConfig) {
|
|
455
|
+
async function scan(dir: string) {
|
|
456
|
+
let entries: Dirent[]
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
entries = await fs.readdir(dir, { withFileTypes: true })
|
|
460
|
+
} catch {
|
|
461
|
+
return
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
await runWithConcurrency(entries, 8, async entry => {
|
|
465
|
+
if (entry.name.startsWith('.') || SKIP_DIRS.has(entry.name)) return
|
|
466
|
+
|
|
467
|
+
const full = path.join(dir, entry.name)
|
|
468
|
+
|
|
469
|
+
if (entry.isDirectory()) {
|
|
470
|
+
await scan(full)
|
|
471
|
+
return
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (!SOURCE_EXTENSIONS.has(path.extname(entry.name))) return
|
|
475
|
+
|
|
476
|
+
await refreshFile(full, config)
|
|
477
|
+
})
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
await scan(root)
|
|
481
|
+
await flushTypes()
|
|
482
|
+
}
|
|
483
|
+
|
|
340
484
|
/**
|
|
341
485
|
* Render collected tags as a module augmentation for the package entrypoint.
|
|
342
486
|
*/
|
|
343
487
|
export function tagsToType(tags: Tags) {
|
|
344
488
|
return [...tags]
|
|
489
|
+
.toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
345
490
|
.map(([tag, classes]) => {
|
|
346
491
|
const union =
|
|
347
492
|
classes.length > 0
|
|
@@ -355,19 +500,3 @@ export function tagsToType(tags: Tags) {
|
|
|
355
500
|
})
|
|
356
501
|
.join('\n')
|
|
357
502
|
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Merge per-file tag maps into one application-wide tag map.
|
|
361
|
-
*/
|
|
362
|
-
export function flattenTags(tagsByFile: BuildContext['tagsByFile']) {
|
|
363
|
-
const tags = new Map<string, string[]>()
|
|
364
|
-
|
|
365
|
-
for (const fileTags of tagsByFile.values()) {
|
|
366
|
-
for (const [name, classes] of fileTags) {
|
|
367
|
-
if (tags.has(name)) throw new DuplicateTagError(name)
|
|
368
|
-
tags.set(name, classes)
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return tags
|
|
373
|
-
}
|
package/src/logger.ts
CHANGED
|
@@ -27,14 +27,9 @@ type LogEntry = {
|
|
|
27
27
|
* Log messages with different severity levels.
|
|
28
28
|
*/
|
|
29
29
|
export class Logger {
|
|
30
|
-
#level: LogLevel
|
|
30
|
+
#level: LogLevel = defaultLevel
|
|
31
31
|
|
|
32
|
-
constructor(
|
|
33
|
-
level?: LogLevel,
|
|
34
|
-
public name?: string,
|
|
35
|
-
) {
|
|
36
|
-
this.#level = level ?? defaultLevel
|
|
37
|
-
}
|
|
32
|
+
constructor(public name?: string) {}
|
|
38
33
|
|
|
39
34
|
/**
|
|
40
35
|
* Convert a value to an Error instance.
|