@venizia/ignis-boot 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/cjs/bun/auto-loader.js +3 -3
  2. package/dist/cjs/bun/auto-loader.js.map +1 -1
  3. package/dist/cjs/bun/group-resolver.js +1 -1
  4. package/dist/cjs/bun/group-resolver.js.map +1 -1
  5. package/dist/cjs/bun/plugin.js +10 -10
  6. package/dist/cjs/bun/plugin.js.map +1 -1
  7. package/dist/cjs/bun/scan-cache.js +1 -1
  8. package/dist/cjs/bun/scan-cache.js.map +1 -1
  9. package/dist/cjs/bun/sources.js +4 -4
  10. package/dist/cjs/bun/sources.js.map +1 -1
  11. package/dist/cjs/clis/artifacts.js +1 -1
  12. package/dist/cjs/clis/artifacts.js.map +1 -1
  13. package/dist/cjs/generator/emitter.js +6 -6
  14. package/dist/cjs/generator/emitter.js.map +1 -1
  15. package/dist/cjs/generator/scanner.d.ts.map +1 -1
  16. package/dist/cjs/generator/scanner.js +10 -8
  17. package/dist/cjs/generator/scanner.js.map +1 -1
  18. package/dist/cjs/vite/plugin.js +3 -3
  19. package/dist/cjs/vite/plugin.js.map +1 -1
  20. package/dist/esm/bun/auto-loader.js +3 -3
  21. package/dist/esm/bun/auto-loader.js.map +1 -1
  22. package/dist/esm/bun/group-resolver.js +1 -1
  23. package/dist/esm/bun/group-resolver.js.map +1 -1
  24. package/dist/esm/bun/plugin.js +10 -10
  25. package/dist/esm/bun/plugin.js.map +1 -1
  26. package/dist/esm/bun/scan-cache.js +1 -1
  27. package/dist/esm/bun/scan-cache.js.map +1 -1
  28. package/dist/esm/bun/sources.js +4 -4
  29. package/dist/esm/bun/sources.js.map +1 -1
  30. package/dist/esm/clis/artifacts.js +1 -1
  31. package/dist/esm/clis/artifacts.js.map +1 -1
  32. package/dist/esm/generator/emitter.js +6 -6
  33. package/dist/esm/generator/emitter.js.map +1 -1
  34. package/dist/esm/generator/scanner.d.ts.map +1 -1
  35. package/dist/esm/generator/scanner.js +10 -8
  36. package/dist/esm/generator/scanner.js.map +1 -1
  37. package/dist/esm/vite/plugin.js +3 -3
  38. package/dist/esm/vite/plugin.js.map +1 -1
  39. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"scan-cache.js","sourceRoot":"","sources":["../../../src/bun/scan-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n existsSync,\n globSync,\n mkdirSync,\n readFileSync,\n renameSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { dirname, join, resolve } from 'node:path';\nimport { ArtifactStereotypes, type IScannedArtifact } from '../generator/common';\n\n/** The scanner's answer for one `src`, kept under the package's `node_modules/.cache` and valid while no `.ts` file under `src`, the package manifest or the lockfile changed - a hit skips TypeScript entirely. */\nexport class ArtifactScanCache {\n static readonly VERSION = 2;\n\n static location(opts: { root: string }): string {\n const root = resolve(opts.root);\n const key = createHash('sha1').update(root).digest('hex').slice(0, 16);\n return join(dirname(root), 'node_modules', '.cache', 'ignis-artifacts', `${key}.json`);\n }\n\n /** Path, size and mtime of every `.ts`/`.tsx` under `root`, plus the package manifest and the nearest lockfile (a dependency upgrade can change which decorators count). */\n static fingerprint(opts: { root: string }): string {\n const root = resolve(opts.root);\n const entries: string[] = [];\n for (const relativePath of globSync(ArtifactStereotypes.SOURCE_GLOB, { cwd: root })) {\n const stats = statSync(join(root, relativePath));\n entries.push(`${relativePath}:${stats.size}:${stats.mtimeMs}`);\n }\n entries.sort();\n\n const extras = [join(dirname(root), 'package.json')];\n let directory = dirname(root);\n while (true) {\n const lockfile = ['bun.lock', 'bun.lockb', 'package-lock.json']\n .map(name => join(directory, name))\n .find(existsSync);\n if (lockfile) {\n extras.push(lockfile);\n break;\n }\n const parent = dirname(directory);\n if (parent === directory) {\n break;\n }\n directory = parent;\n }\n for (const file of extras.filter(existsSync)) {\n const stats = statSync(file);\n entries.push(`${file}:${stats.size}:${stats.mtimeMs}`);\n }\n\n return createHash('sha1')\n .update(`${ArtifactScanCache.VERSION}\\n${entries.join('\\n')}`)\n .digest('hex');\n }\n\n /** The cached scan, or `undefined` for a missing, stale or unreadable cache - never an error. */\n static read(opts: { root: string }): IScannedArtifact[] | undefined {\n const file = ArtifactScanCache.location(opts);\n if (!existsSync(file)) {\n return undefined;\n }\n let stored: { fingerprint?: unknown; artifacts?: unknown };\n try {\n stored = JSON.parse(readFileSync(file, 'utf8'));\n } catch {\n // A corrupt cache is a miss: the caller scans and rewrites it.\n return undefined;\n }\n if (\n stored.fingerprint !== ArtifactScanCache.fingerprint(opts) ||\n !Array.isArray(stored.artifacts)\n ) {\n return undefined;\n }\n return stored.artifacts;\n }\n\n /** Stores a scan; `false` when the cache directory cannot be written (a read-only install), which only costs the next start a scan. */\n static write(opts: { root: string; artifacts: IScannedArtifact[] }): boolean {\n const file = ArtifactScanCache.location(opts);\n const temporary = `${file}.${process.pid}.tmp`;\n try {\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(\n temporary,\n JSON.stringify({\n fingerprint: ArtifactScanCache.fingerprint(opts),\n artifacts: opts.artifacts,\n }),\n );\n renameSync(temporary, file);\n return true;\n } catch {\n // Caching is an optimisation; reporting `false` lets the caller go on with the scan it already has.\n return false;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"scan-cache.js","sourceRoot":"","sources":["../../../src/bun/scan-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n existsSync,\n globSync,\n mkdirSync,\n readFileSync,\n renameSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { dirname, join, resolve } from 'node:path';\nimport { ArtifactStereotypes, type IScannedArtifact } from '../generator/common';\n\n/** The scanner's answer for one `src`, kept under the package's `node_modules/.cache` and valid while no `.ts` file under `src`, the package manifest or the lockfile changed - a hit skips TypeScript entirely. */\nexport class ArtifactScanCache {\n static readonly VERSION = 2;\n\n static location(opts: { root: string }): string {\n const root = resolve(opts.root);\n const key = createHash('sha1').update(root).digest('hex').slice(0, 16);\n return join(dirname(root), 'node_modules', '.cache', 'ignis-artifacts', `${key}.json`);\n }\n\n /** Path, size and mtime of every `.ts`/`.tsx` under `root`, plus the package manifest and the nearest lockfile (a dependency upgrade can change which decorators count). */\n static fingerprint(opts: { root: string }): string {\n const root = resolve(opts.root);\n const entries: string[] = [];\n for (const relativePath of globSync(ArtifactStereotypes.SOURCE_GLOB, { cwd: root })) {\n const stats = statSync(join(root, relativePath));\n entries.push(`${relativePath}:${stats.size}:${stats.mtimeMs}`);\n }\n entries.sort();\n\n const extras = [join(dirname(root), 'package.json')];\n let directory = dirname(root);\n while (true) {\n const lockfile = ['bun.lock', 'bun.lockb', 'package-lock.json']\n .map((name) => join(directory, name))\n .find(existsSync);\n if (lockfile) {\n extras.push(lockfile);\n break;\n }\n const parent = dirname(directory);\n if (parent === directory) {\n break;\n }\n directory = parent;\n }\n for (const file of extras.filter(existsSync)) {\n const stats = statSync(file);\n entries.push(`${file}:${stats.size}:${stats.mtimeMs}`);\n }\n\n return createHash('sha1')\n .update(`${ArtifactScanCache.VERSION}\\n${entries.join('\\n')}`)\n .digest('hex');\n }\n\n /** The cached scan, or `undefined` for a missing, stale or unreadable cache - never an error. */\n static read(opts: { root: string }): IScannedArtifact[] | undefined {\n const file = ArtifactScanCache.location(opts);\n if (!existsSync(file)) {\n return undefined;\n }\n let stored: { fingerprint?: unknown; artifacts?: unknown };\n try {\n stored = JSON.parse(readFileSync(file, 'utf8'));\n } catch {\n // A corrupt cache is a miss: the caller scans and rewrites it.\n return undefined;\n }\n if (\n stored.fingerprint !== ArtifactScanCache.fingerprint(opts) ||\n !Array.isArray(stored.artifacts)\n ) {\n return undefined;\n }\n return stored.artifacts;\n }\n\n /** Stores a scan; `false` when the cache directory cannot be written (a read-only install), which only costs the next start a scan. */\n static write(opts: { root: string; artifacts: IScannedArtifact[] }): boolean {\n const file = ArtifactScanCache.location(opts);\n const temporary = `${file}.${process.pid}.tmp`;\n try {\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(\n temporary,\n JSON.stringify({\n fingerprint: ArtifactScanCache.fingerprint(opts),\n artifacts: opts.artifacts,\n }),\n );\n renameSync(temporary, file);\n return true;\n } catch {\n // Caching is an optimisation; reporting `false` lets the caller go on with the scan it already has.\n return false;\n }\n }\n}\n"]}
@@ -72,10 +72,10 @@ export class ArtifactSources {
72
72
  const artifacts = ArtifactSources.scan({ packageSource });
73
73
  const { folder } = opts;
74
74
  const ignored = opts.ignore ?? [];
75
- const picked = artifacts.filter(artifact => {
75
+ const picked = artifacts.filter((artifact) => {
76
76
  const path = relative(packageSource, artifact.filePath);
77
77
  return ((folder === undefined || path.split(sep).slice(0, -1).includes(folder)) &&
78
- !ignored.some(pattern => matchesGlob(path, pattern)));
78
+ !ignored.some((pattern) => matchesGlob(path, pattern)));
79
79
  });
80
80
  return ArtifactSources.runningArtifacts({ artifacts: picked, from: opts.site });
81
81
  }
@@ -92,8 +92,8 @@ export class ArtifactSources {
92
92
  const segments = relative(packageRoot, dirname(from)).split(sep);
93
93
  const tree = segments
94
94
  .map((_segment, index) => join(packageRoot, ...segments.slice(0, index + 1)))
95
- .find(candidate => existsSync(compiledPath({ tree: candidate, artifact: probe })));
96
- return opts.artifacts.map(artifact => {
95
+ .find((candidate) => existsSync(compiledPath({ tree: candidate, artifact: probe })));
96
+ return opts.artifacts.map((artifact) => {
97
97
  const compiled = tree ? compiledPath({ tree, artifact }) : undefined;
98
98
  if (!compiled || !existsSync(compiled)) {
99
99
  throw getError({
@@ -1 +1 @@
1
- {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../../src/bun/sources.ts"],"names":[],"mappings":"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","sourcesContent":["import { getError } from '@venizia/ignis-helpers';\nimport { existsSync } from 'node:fs';\nimport { dirname, join, matchesGlob, relative, resolve, sep } from 'node:path';\nimport { ArtifactStereotypes, type IScannedArtifact } from '../generator/common';\nimport { ArtifactScanCache } from './scan-cache';\n\ninterface IArtifactScanner {\n scanWithReport(opts: { root: string; followReexports: boolean }): {\n artifacts: IScannedArtifact[];\n };\n}\n\n/** Where a package's artifacts live: the `src` beside its nearest `package.json`, and the classes under one of its directories. One scan per package per process, served from `ArtifactScanCache` when no source file changed - so this module never loads the scanner (and TypeScript) itself. */\nexport class ArtifactSources {\n private static readonly scans = new Map<string, IScannedArtifact[]>();\n private static scanner: IArtifactScanner | undefined;\n\n /** Called by the modules that already hold the scanner (the build plugin). */\n static useScanner(opts: { scanner: IArtifactScanner }): void {\n ArtifactSources.scanner = opts.scanner;\n }\n\n /** Loads the scanner - only on a cache miss. A non-static specifier, so a bundle never pulls TypeScript in. */\n static async loadScanner(): Promise<void> {\n if (ArtifactSources.scanner) {\n return;\n }\n const generatorModule = '../generator';\n const { ArtifactScanner } = await import(generatorModule);\n ArtifactSources.scanner = ArtifactScanner.getInstance();\n }\n\n /** Whether `packageSource` can be listed without the scanner: scanned in this process, or a valid disk cache. */\n static isCached(opts: { packageSource: string }): boolean {\n if (ArtifactSources.scans.has(opts.packageSource)) {\n return true;\n }\n const cached = ArtifactScanCache.read({ root: opts.packageSource });\n if (cached) {\n ArtifactSources.scans.set(opts.packageSource, cached);\n }\n return cached !== undefined;\n }\n\n /** Every decorated class under `packageSource`: this process's scan, else the disk cache, else the scanner (which must be loaded), written back to the cache. */\n static scan(opts: { packageSource: string }): IScannedArtifact[] {\n const { packageSource } = opts;\n if (ArtifactSources.isCached({ packageSource })) {\n return ArtifactSources.scans.get(packageSource) ?? [];\n }\n if (!ArtifactSources.scanner) {\n throw getError({\n message: `[ArtifactSources] ${packageSource} is not cached and the scanner is not loaded | Call ArtifactSources.loadScanner() first`,\n });\n }\n const { artifacts } = ArtifactSources.scanner.scanWithReport({\n root: packageSource,\n followReexports: true,\n });\n ArtifactSources.scans.set(packageSource, artifacts);\n ArtifactScanCache.write({ root: packageSource, artifacts });\n return artifacts;\n }\n\n /** The entry module (`Bun.main`), or `undefined` when there is no entry file (`bun -e`, a REPL). */\n static entry(): string | undefined {\n return typeof Bun !== 'undefined' && existsSync(Bun.main) ? Bun.main : undefined;\n }\n\n /** The `src` beside the nearest `package.json` at or above `from` (default: the working directory). */\n static packageSource(opts: { from?: string } = {}): string {\n const start = resolve(opts.from ?? process.cwd());\n let directory = start;\n while (!existsSync(join(directory, 'package.json'))) {\n const parent = dirname(directory);\n if (parent === directory) {\n return join(start, 'src');\n }\n directory = parent;\n }\n return join(directory, 'src');\n }\n\n /** The decorated classes under a directory named `folder` in the package whose source holds `site`, less those under an `ignore` glob (relative to `src`), each pointing at the copy that runs beside `site` (see `runningArtifacts`). */\n static folderArtifacts(opts: {\n folder: string | undefined;\n site: string;\n ignore?: ReadonlyArray<string>;\n }): IScannedArtifact[] {\n const packageSource = ArtifactSources.packageSource({ from: dirname(opts.site) });\n\n const artifacts = ArtifactSources.scan({ packageSource });\n\n const { folder } = opts;\n const ignored = opts.ignore ?? [];\n const picked = artifacts.filter(artifact => {\n const path = relative(packageSource, artifact.filePath);\n return (\n (folder === undefined || path.split(sep).slice(0, -1).includes(folder)) &&\n !ignored.some(pattern => matchesGlob(path, pattern))\n );\n });\n return ArtifactSources.runningArtifacts({ artifacts: picked, from: opts.site });\n }\n\n /** The scanned classes as the code at `from` runs them: unchanged when `from` is in `src`; otherwise each `src/<path>.ts` becomes `<tree>/<path>.js` in the compiled tree `from` sits in (`dist`, `dist/esm`), so an application registers the very class its code uses, never a second copy loaded from `src`. */\n static runningArtifacts(opts: {\n artifacts: IScannedArtifact[];\n from: string;\n }): IScannedArtifact[] {\n const from = resolve(opts.from);\n const packageSource = ArtifactSources.packageSource({ from: dirname(from) });\n const [probe] = opts.artifacts;\n if (!probe || from.startsWith(`${packageSource}${sep}`)) {\n return opts.artifacts;\n }\n\n const packageRoot = dirname(packageSource);\n const compiledPath = (target: { tree: string; artifact: IScannedArtifact }): string =>\n join(\n target.tree,\n relative(packageSource, target.artifact.filePath).replace(\n ArtifactStereotypes.SOURCE_EXTENSION,\n '.js',\n ),\n );\n const segments = relative(packageRoot, dirname(from)).split(sep);\n const tree = segments\n .map((_segment, index) => join(packageRoot, ...segments.slice(0, index + 1)))\n .find(candidate => existsSync(compiledPath({ tree: candidate, artifact: probe })));\n\n return opts.artifacts.map(artifact => {\n const compiled = tree ? compiledPath({ tree, artifact }) : undefined;\n if (!compiled || !existsSync(compiled)) {\n throw getError({\n message: `[ArtifactSources] ${artifact.filePath} has no compiled copy beside ${from} | The package runs from a compiled tree that is older than its src - rebuild it (or run it from src)`,\n });\n }\n return { ...artifact, filePath: compiled };\n });\n }\n\n /** Forgets every cached scan - for a long-lived process that rebuilds (a watch mode). */\n static clear(): void {\n ArtifactSources.scans.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../../src/bun/sources.ts"],"names":[],"mappings":"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","sourcesContent":["import { getError } from '@venizia/ignis-helpers';\nimport { existsSync } from 'node:fs';\nimport { dirname, join, matchesGlob, relative, resolve, sep } from 'node:path';\nimport { ArtifactStereotypes, type IScannedArtifact } from '../generator/common';\nimport { ArtifactScanCache } from './scan-cache';\n\ninterface IArtifactScanner {\n scanWithReport(opts: { root: string; followReexports: boolean }): {\n artifacts: IScannedArtifact[];\n };\n}\n\n/** Where a package's artifacts live: the `src` beside its nearest `package.json`, and the classes under one of its directories. One scan per package per process, served from `ArtifactScanCache` when no source file changed - so this module never loads the scanner (and TypeScript) itself. */\nexport class ArtifactSources {\n private static readonly scans = new Map<string, IScannedArtifact[]>();\n private static scanner: IArtifactScanner | undefined;\n\n /** Called by the modules that already hold the scanner (the build plugin). */\n static useScanner(opts: { scanner: IArtifactScanner }): void {\n ArtifactSources.scanner = opts.scanner;\n }\n\n /** Loads the scanner - only on a cache miss. A non-static specifier, so a bundle never pulls TypeScript in. */\n static async loadScanner(): Promise<void> {\n if (ArtifactSources.scanner) {\n return;\n }\n const generatorModule = '../generator';\n const { ArtifactScanner } = await import(generatorModule);\n ArtifactSources.scanner = ArtifactScanner.getInstance();\n }\n\n /** Whether `packageSource` can be listed without the scanner: scanned in this process, or a valid disk cache. */\n static isCached(opts: { packageSource: string }): boolean {\n if (ArtifactSources.scans.has(opts.packageSource)) {\n return true;\n }\n const cached = ArtifactScanCache.read({ root: opts.packageSource });\n if (cached) {\n ArtifactSources.scans.set(opts.packageSource, cached);\n }\n return cached !== undefined;\n }\n\n /** Every decorated class under `packageSource`: this process's scan, else the disk cache, else the scanner (which must be loaded), written back to the cache. */\n static scan(opts: { packageSource: string }): IScannedArtifact[] {\n const { packageSource } = opts;\n if (ArtifactSources.isCached({ packageSource })) {\n return ArtifactSources.scans.get(packageSource) ?? [];\n }\n if (!ArtifactSources.scanner) {\n throw getError({\n message: `[ArtifactSources] ${packageSource} is not cached and the scanner is not loaded | Call ArtifactSources.loadScanner() first`,\n });\n }\n const { artifacts } = ArtifactSources.scanner.scanWithReport({\n root: packageSource,\n followReexports: true,\n });\n ArtifactSources.scans.set(packageSource, artifacts);\n ArtifactScanCache.write({ root: packageSource, artifacts });\n return artifacts;\n }\n\n /** The entry module (`Bun.main`), or `undefined` when there is no entry file (`bun -e`, a REPL). */\n static entry(): string | undefined {\n return typeof Bun !== 'undefined' && existsSync(Bun.main) ? Bun.main : undefined;\n }\n\n /** The `src` beside the nearest `package.json` at or above `from` (default: the working directory). */\n static packageSource(opts: { from?: string } = {}): string {\n const start = resolve(opts.from ?? process.cwd());\n let directory = start;\n while (!existsSync(join(directory, 'package.json'))) {\n const parent = dirname(directory);\n if (parent === directory) {\n return join(start, 'src');\n }\n directory = parent;\n }\n return join(directory, 'src');\n }\n\n /** The decorated classes under a directory named `folder` in the package whose source holds `site`, less those under an `ignore` glob (relative to `src`), each pointing at the copy that runs beside `site` (see `runningArtifacts`). */\n static folderArtifacts(opts: {\n folder: string | undefined;\n site: string;\n ignore?: ReadonlyArray<string>;\n }): IScannedArtifact[] {\n const packageSource = ArtifactSources.packageSource({ from: dirname(opts.site) });\n\n const artifacts = ArtifactSources.scan({ packageSource });\n\n const { folder } = opts;\n const ignored = opts.ignore ?? [];\n const picked = artifacts.filter((artifact) => {\n const path = relative(packageSource, artifact.filePath);\n return (\n (folder === undefined || path.split(sep).slice(0, -1).includes(folder)) &&\n !ignored.some((pattern) => matchesGlob(path, pattern))\n );\n });\n return ArtifactSources.runningArtifacts({ artifacts: picked, from: opts.site });\n }\n\n /** The scanned classes as the code at `from` runs them: unchanged when `from` is in `src`; otherwise each `src/<path>.ts` becomes `<tree>/<path>.js` in the compiled tree `from` sits in (`dist`, `dist/esm`), so an application registers the very class its code uses, never a second copy loaded from `src`. */\n static runningArtifacts(opts: {\n artifacts: IScannedArtifact[];\n from: string;\n }): IScannedArtifact[] {\n const from = resolve(opts.from);\n const packageSource = ArtifactSources.packageSource({ from: dirname(from) });\n const [probe] = opts.artifacts;\n if (!probe || from.startsWith(`${packageSource}${sep}`)) {\n return opts.artifacts;\n }\n\n const packageRoot = dirname(packageSource);\n const compiledPath = (target: { tree: string; artifact: IScannedArtifact }): string =>\n join(\n target.tree,\n relative(packageSource, target.artifact.filePath).replace(\n ArtifactStereotypes.SOURCE_EXTENSION,\n '.js',\n ),\n );\n const segments = relative(packageRoot, dirname(from)).split(sep);\n const tree = segments\n .map((_segment, index) => join(packageRoot, ...segments.slice(0, index + 1)))\n .find((candidate) => existsSync(compiledPath({ tree: candidate, artifact: probe })));\n\n return opts.artifacts.map((artifact) => {\n const compiled = tree ? compiledPath({ tree, artifact }) : undefined;\n if (!compiled || !existsSync(compiled)) {\n throw getError({\n message: `[ArtifactSources] ${artifact.filePath} has no compiled copy beside ${from} | The package runs from a compiled tree that is older than its src - rebuild it (or run it from src)`,\n });\n }\n return { ...artifact, filePath: compiled };\n });\n }\n\n /** Forgets every cached scan - for a long-lived process that rebuilds (a watch mode). */\n static clear(): void {\n ArtifactSources.scans.clear();\n }\n}\n"]}
@@ -20,7 +20,7 @@ const options = {
20
20
  out: values.out,
21
21
  ignore: values.ignore
22
22
  ?.split(',')
23
- .map(pattern => pattern.trim())
23
+ .map((pattern) => pattern.trim())
24
24
  .filter(Boolean),
25
25
  exportName: values.export,
26
26
  sourceModules: values['source-module'],
@@ -1 +1 @@
1
- {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../../src/clis/artifacts.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env bun\nimport '../common/install-quiet-logger';\nimport { relative } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { ArtifactIndexEmitter, checkArtifactIndex, generateArtifactIndex } from '../generator';\nimport type { IScannedArtifact } from '../generator';\n\nconst USAGE =\n 'ignis-artifacts <generate|check> [--root src] [--out src/generated/artifacts.ts] [--ignore a,b] [--export GeneratedArtifacts] [--source-module <specifier>]...';\n\nconst { positionals, values } = parseArgs({\n args: process.argv.slice(2),\n allowPositionals: true,\n options: {\n root: { type: 'string', default: 'src' },\n out: { type: 'string', default: 'src/generated/artifacts.ts' },\n ignore: { type: 'string' },\n export: { type: 'string', default: 'GeneratedArtifacts' },\n 'source-module': { type: 'string', multiple: true },\n },\n});\n\nconst options = {\n root: values.root,\n out: values.out,\n ignore: values.ignore\n ?.split(',')\n .map(pattern => pattern.trim())\n .filter(Boolean),\n exportName: values.export,\n sourceModules: values['source-module'],\n};\n\n/** One stderr line per decorated class a user `--ignore` pattern hid; silence when nothing is hidden. */\nconst warnIgnored = (opts: { ignored: IScannedArtifact[]; root: string }): void => {\n for (const artifact of opts.ignored) {\n console.error(\n `warning: ${artifact.className} (${artifact.type}) in ${relative(opts.root, artifact.filePath)} matches --ignore and is left out of the index`,\n );\n }\n};\n\n/** Exit code of the command, so the process exits in exactly one place. */\nconst run = (): number => {\n switch (positionals[0]) {\n case 'generate': {\n const result = generateArtifactIndex(options);\n console.log(\n `${result.written ? 'wrote' : 'up to date'} ${options.out} | ${result.artifacts.length} artifact(s)`,\n );\n warnIgnored({ ignored: result.ignored, root: options.root });\n return 0;\n }\n case 'check': {\n const result = checkArtifactIndex(options);\n warnIgnored({ ignored: result.ignored, root: options.root });\n if (result.isFresh) {\n console.log(`fresh ${options.out}`);\n return 0;\n }\n console.error(`stale ${options.out} - run: ${ArtifactIndexEmitter.renderCommand(options)}`);\n return 1;\n }\n default: {\n console.error(USAGE);\n return 2;\n }\n }\n};\n\nprocess.exit(run());\n"]}
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../../src/clis/artifacts.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env bun\nimport '../common/install-quiet-logger';\nimport { relative } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { ArtifactIndexEmitter, checkArtifactIndex, generateArtifactIndex } from '../generator';\nimport type { IScannedArtifact } from '../generator';\n\nconst USAGE =\n 'ignis-artifacts <generate|check> [--root src] [--out src/generated/artifacts.ts] [--ignore a,b] [--export GeneratedArtifacts] [--source-module <specifier>]...';\n\nconst { positionals, values } = parseArgs({\n args: process.argv.slice(2),\n allowPositionals: true,\n options: {\n root: { type: 'string', default: 'src' },\n out: { type: 'string', default: 'src/generated/artifacts.ts' },\n ignore: { type: 'string' },\n export: { type: 'string', default: 'GeneratedArtifacts' },\n 'source-module': { type: 'string', multiple: true },\n },\n});\n\nconst options = {\n root: values.root,\n out: values.out,\n ignore: values.ignore\n ?.split(',')\n .map((pattern) => pattern.trim())\n .filter(Boolean),\n exportName: values.export,\n sourceModules: values['source-module'],\n};\n\n/** One stderr line per decorated class a user `--ignore` pattern hid; silence when nothing is hidden. */\nconst warnIgnored = (opts: { ignored: IScannedArtifact[]; root: string }): void => {\n for (const artifact of opts.ignored) {\n console.error(\n `warning: ${artifact.className} (${artifact.type}) in ${relative(opts.root, artifact.filePath)} matches --ignore and is left out of the index`,\n );\n }\n};\n\n/** Exit code of the command, so the process exits in exactly one place. */\nconst run = (): number => {\n switch (positionals[0]) {\n case 'generate': {\n const result = generateArtifactIndex(options);\n console.log(\n `${result.written ? 'wrote' : 'up to date'} ${options.out} | ${result.artifacts.length} artifact(s)`,\n );\n warnIgnored({ ignored: result.ignored, root: options.root });\n return 0;\n }\n case 'check': {\n const result = checkArtifactIndex(options);\n warnIgnored({ ignored: result.ignored, root: options.root });\n if (result.isFresh) {\n console.log(`fresh ${options.out}`);\n return 0;\n }\n console.error(`stale ${options.out} - run: ${ArtifactIndexEmitter.renderCommand(options)}`);\n return 1;\n }\n default: {\n console.error(USAGE);\n return 2;\n }\n }\n};\n\nprocess.exit(run());\n"]}
@@ -26,9 +26,9 @@ export class ArtifactIndexEmitter {
26
26
  }
27
27
  static render(opts) {
28
28
  const { artifacts, outFile, exportName, command } = opts;
29
- const emitted = artifacts.filter(artifact => artifact.type !== ArtifactTypes.MODEL);
29
+ const emitted = artifacts.filter((artifact) => artifact.type !== ArtifactTypes.MODEL);
30
30
  const imports = emitted
31
- .map(artifact => ({
31
+ .map((artifact) => ({
32
32
  name: artifact.className,
33
33
  path: ArtifactIndexEmitter.importPath({
34
34
  from: outFile,
@@ -37,11 +37,11 @@ export class ArtifactIndexEmitter {
37
37
  }),
38
38
  }))
39
39
  .sort((a, b) => a.path.localeCompare(b.path) || a.name.localeCompare(b.name))
40
- .map(entry => `import { ${entry.name} } from '${entry.path}';`);
40
+ .map((entry) => `import { ${entry.name} } from '${entry.path}';`);
41
41
  const fields = ArtifactStereotypes.EMIT_ORDER.flatMap(({ type, field }) => {
42
42
  const names = emitted
43
- .filter(artifact => artifact.type === type)
44
- .map(artifact => artifact.className)
43
+ .filter((artifact) => artifact.type === type)
44
+ .map((artifact) => artifact.className)
45
45
  .sort((a, b) => a.localeCompare(b));
46
46
  return ArtifactIndexEmitter.renderField({ field, names });
47
47
  });
@@ -62,7 +62,7 @@ export class ArtifactIndexEmitter {
62
62
  if (singleLine.length <= ArtifactIndexEmitter.PRINT_WIDTH) {
63
63
  return [singleLine];
64
64
  }
65
- return [` ${field}: [`, ...names.map(name => ` ${name},`), ' ],'];
65
+ return [` ${field}: [`, ...names.map((name) => ` ${name},`), ' ],'];
66
66
  }
67
67
  static importPath(opts) {
68
68
  if (opts.isAbsolute) {
@@ -1 +1 @@
1
- {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../../src/generator/emitter.ts"],"names":[],"mappings":"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","sourcesContent":["import { dirname, relative, sep } from 'node:path';\nimport { ArtifactStereotypes, ArtifactTypes, type IScannedArtifact } from './common';\n\n/** Renders the generated index: deterministic text, plain static imports, no IGNIS import - the object is type-checked where `registerArtifacts` receives it. */\nexport class ArtifactIndexEmitter {\n /** Mirrors `printWidth` in the root bunfig.toml `[fmt]` table. */\n static readonly PRINT_WIDTH = 100;\n\n static readonly DEFAULT_EXPORT_NAME = 'GeneratedArtifacts';\n\n /** The `ignis-artifacts generate` command for these options - the header and the CLI's stale hint print the same one. */\n static renderCommand(opts: {\n root: string;\n out: string;\n ignore?: string[];\n exportName?: string;\n sourceModules?: string[];\n }): string {\n const { root, out, ignore = [], exportName, sourceModules = [] } = opts;\n const flags = [`--root ${root}`, `--out ${out}`];\n if (ignore.length > 0) {\n flags.push(`--ignore ${ignore.join(',')}`);\n }\n if (exportName && exportName !== ArtifactIndexEmitter.DEFAULT_EXPORT_NAME) {\n flags.push(`--export ${exportName}`);\n }\n for (const sourceModule of sourceModules) {\n flags.push(`--source-module ${sourceModule}`);\n }\n return `ignis-artifacts generate ${flags.join(' ')}`;\n }\n\n /** The exact command that regenerates the file, so the header never points at another path than the one the build used. */\n static renderHeader(opts: {\n root: string;\n out: string;\n ignore?: string[];\n exportName?: string;\n sourceModules?: string[];\n }): string {\n return `// AUTO-GENERATED by @venizia/ignis-boot - do not edit. Regenerate: ${ArtifactIndexEmitter.renderCommand(opts)}`;\n }\n\n static render(opts: {\n artifacts: IScannedArtifact[];\n outFile: string;\n exportName: string;\n /** Absolute import paths - for a virtual module, which has no directory to resolve a relative one from. */\n absoluteImports?: boolean;\n /** The CLI arguments as given, for the header; `outFile` above is the resolved path used for import specifiers. */\n command: { root: string; out: string; ignore?: string[]; sourceModules?: string[] };\n }): string {\n const { artifacts, outFile, exportName, command } = opts;\n const emitted = artifacts.filter(artifact => artifact.type !== ArtifactTypes.MODEL);\n\n const imports = emitted\n .map(artifact => ({\n name: artifact.className,\n path: ArtifactIndexEmitter.importPath({\n from: outFile,\n to: artifact.filePath,\n isAbsolute: opts.absoluteImports ?? false,\n }),\n }))\n .sort((a, b) => a.path.localeCompare(b.path) || a.name.localeCompare(b.name))\n .map(entry => `import { ${entry.name} } from '${entry.path}';`);\n\n const fields = ArtifactStereotypes.EMIT_ORDER.flatMap(({ type, field }) => {\n const names = emitted\n .filter(artifact => artifact.type === type)\n .map(artifact => artifact.className)\n .sort((a, b) => a.localeCompare(b));\n\n return ArtifactIndexEmitter.renderField({ field, names });\n });\n\n return [\n ArtifactIndexEmitter.renderHeader({ ...command, exportName }),\n ...imports,\n '',\n `export const ${exportName} = {`,\n ...fields,\n '};',\n '',\n ].join('\\n');\n }\n\n /** One line while it fits the print width, else one name per line - so `bun fmt --check` on the generated file stays quiet. */\n private static renderField(opts: { field: string; names: string[] }): string[] {\n const { field, names } = opts;\n const singleLine = ` ${field}: [${names.join(', ')}],`;\n\n if (singleLine.length <= ArtifactIndexEmitter.PRINT_WIDTH) {\n return [singleLine];\n }\n\n return [` ${field}: [`, ...names.map(name => ` ${name},`), ' ],'];\n }\n\n private static importPath(opts: { from: string; to: string; isAbsolute: boolean }): string {\n if (opts.isAbsolute) {\n return opts.to.split(sep).join('/').replace(ArtifactStereotypes.SOURCE_EXTENSION, '');\n }\n const raw = relative(dirname(opts.from), opts.to)\n .split(sep)\n .join('/')\n .replace(ArtifactStereotypes.SOURCE_EXTENSION, '');\n return raw.startsWith('.') ? raw : `./${raw}`;\n }\n}\n"]}
1
+ {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../../src/generator/emitter.ts"],"names":[],"mappings":"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","sourcesContent":["import { dirname, relative, sep } from 'node:path';\nimport { ArtifactStereotypes, ArtifactTypes, type IScannedArtifact } from './common';\n\n/** Renders the generated index: deterministic text, plain static imports, no IGNIS import - the object is type-checked where `registerArtifacts` receives it. */\nexport class ArtifactIndexEmitter {\n /** Mirrors `printWidth` in the root bunfig.toml `[fmt]` table. */\n static readonly PRINT_WIDTH = 100;\n\n static readonly DEFAULT_EXPORT_NAME = 'GeneratedArtifacts';\n\n /** The `ignis-artifacts generate` command for these options - the header and the CLI's stale hint print the same one. */\n static renderCommand(opts: {\n root: string;\n out: string;\n ignore?: string[];\n exportName?: string;\n sourceModules?: string[];\n }): string {\n const { root, out, ignore = [], exportName, sourceModules = [] } = opts;\n const flags = [`--root ${root}`, `--out ${out}`];\n if (ignore.length > 0) {\n flags.push(`--ignore ${ignore.join(',')}`);\n }\n if (exportName && exportName !== ArtifactIndexEmitter.DEFAULT_EXPORT_NAME) {\n flags.push(`--export ${exportName}`);\n }\n for (const sourceModule of sourceModules) {\n flags.push(`--source-module ${sourceModule}`);\n }\n return `ignis-artifacts generate ${flags.join(' ')}`;\n }\n\n /** The exact command that regenerates the file, so the header never points at another path than the one the build used. */\n static renderHeader(opts: {\n root: string;\n out: string;\n ignore?: string[];\n exportName?: string;\n sourceModules?: string[];\n }): string {\n return `// AUTO-GENERATED by @venizia/ignis-boot - do not edit. Regenerate: ${ArtifactIndexEmitter.renderCommand(opts)}`;\n }\n\n static render(opts: {\n artifacts: IScannedArtifact[];\n outFile: string;\n exportName: string;\n /** Absolute import paths - for a virtual module, which has no directory to resolve a relative one from. */\n absoluteImports?: boolean;\n /** The CLI arguments as given, for the header; `outFile` above is the resolved path used for import specifiers. */\n command: { root: string; out: string; ignore?: string[]; sourceModules?: string[] };\n }): string {\n const { artifacts, outFile, exportName, command } = opts;\n const emitted = artifacts.filter((artifact) => artifact.type !== ArtifactTypes.MODEL);\n\n const imports = emitted\n .map((artifact) => ({\n name: artifact.className,\n path: ArtifactIndexEmitter.importPath({\n from: outFile,\n to: artifact.filePath,\n isAbsolute: opts.absoluteImports ?? false,\n }),\n }))\n .sort((a, b) => a.path.localeCompare(b.path) || a.name.localeCompare(b.name))\n .map((entry) => `import { ${entry.name} } from '${entry.path}';`);\n\n const fields = ArtifactStereotypes.EMIT_ORDER.flatMap(({ type, field }) => {\n const names = emitted\n .filter((artifact) => artifact.type === type)\n .map((artifact) => artifact.className)\n .sort((a, b) => a.localeCompare(b));\n\n return ArtifactIndexEmitter.renderField({ field, names });\n });\n\n return [\n ArtifactIndexEmitter.renderHeader({ ...command, exportName }),\n ...imports,\n '',\n `export const ${exportName} = {`,\n ...fields,\n '};',\n '',\n ].join('\\n');\n }\n\n /** One line while it fits the print width, else one name per line - so `bun fmt --check` on the generated file stays quiet. */\n private static renderField(opts: { field: string; names: string[] }): string[] {\n const { field, names } = opts;\n const singleLine = ` ${field}: [${names.join(', ')}],`;\n\n if (singleLine.length <= ArtifactIndexEmitter.PRINT_WIDTH) {\n return [singleLine];\n }\n\n return [` ${field}: [`, ...names.map((name) => ` ${name},`), ' ],'];\n }\n\n private static importPath(opts: { from: string; to: string; isAbsolute: boolean }): string {\n if (opts.isAbsolute) {\n return opts.to.split(sep).join('/').replace(ArtifactStereotypes.SOURCE_EXTENSION, '');\n }\n const raw = relative(dirname(opts.from), opts.to)\n .split(sep)\n .join('/')\n .replace(ArtifactStereotypes.SOURCE_EXTENSION, '');\n return raw.startsWith('.') ? raw : `./${raw}`;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/generator/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,wBAAwB,CAAC;AAI9D,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EAEtB,MAAM,UAAU,CAAC;AAGlB,yGAAyG;AACzG,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAkB;IAE1C,OAAO;IAIP,MAAM,CAAC,WAAW,IAAI,eAAe;IAIrC,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAI5C,+JAA+J;IAC/J,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW;IA8B/C,oIAAoI;IACpI,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,aAAa;IAMrB,uJAAuJ;IACvJ,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,QAAQ;IAgFhB,sIAAsI;IACtI,OAAO,CAAC,wBAAwB;IAkDhC,6HAA6H;IAC7H,OAAO,CAAC,0BAA0B;IAgBlC,OAAO,CAAC,wBAAwB;IAkBhC,OAAO,CAAC,eAAe;IA0CvB,OAAO,CAAC,oBAAoB;IA6B5B,OAAO,CAAC,cAAc;CAMvB"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/generator/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,wBAAwB,CAAC;AAI9D,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EAEtB,MAAM,UAAU,CAAC;AAGlB,yGAAyG;AACzG,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAkB;IAE1C,OAAO;IAIP,MAAM,CAAC,WAAW,IAAI,eAAe;IAIrC,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAI5C,+JAA+J;IAC/J,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW;IA8B/C,oIAAoI;IACpI,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,aAAa;IAMrB,uJAAuJ;IACvJ,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,QAAQ;IAgFhB,sIAAsI;IACtI,OAAO,CAAC,wBAAwB;IAkDhC,6HAA6H;IAC7H,OAAO,CAAC,0BAA0B;IAgBlC,OAAO,CAAC,wBAAwB;IAkBhC,OAAO,CAAC,eAAe;IA0CvB,OAAO,CAAC,oBAAoB;IA6B5B,OAAO,CAAC,cAAc;CAMvB"}
@@ -28,8 +28,8 @@ export class ArtifactScanner extends BaseHelper {
28
28
  ? new StereotypeReexportResolver({ root, sourceModules })
29
29
  : undefined;
30
30
  const skipped = [];
31
- const artifacts = this.sortArtifacts(kept.flatMap(filePath => this.scanFile({ filePath, sourceModules, resolver, skipped })));
32
- const ignored = this.sortArtifacts(hidden.flatMap(filePath => this.scanHiddenFile({ filePath, sourceModules, resolver })));
31
+ const artifacts = this.sortArtifacts(kept.flatMap((filePath) => this.scanFile({ filePath, sourceModules, resolver, skipped })));
32
+ const ignored = this.sortArtifacts(hidden.flatMap((filePath) => this.scanHiddenFile({ filePath, sourceModules, resolver })));
33
33
  for (const artifact of ignored) {
34
34
  skipped.push({
35
35
  className: artifact.className,
@@ -60,10 +60,12 @@ export class ArtifactScanner extends BaseHelper {
60
60
  const sources = globSync(ArtifactStereotypes.SOURCE_GLOB, { cwd: opts.root });
61
61
  for (const relative of sources) {
62
62
  if (relative.endsWith('.d.ts') ||
63
- opts.defaultGlobs.some(pattern => matchesGlob(relative, pattern))) {
63
+ opts.defaultGlobs.some((pattern) => matchesGlob(relative, pattern))) {
64
64
  continue;
65
65
  }
66
- const target = opts.userGlobs.some(pattern => matchesGlob(relative, pattern)) ? hidden : kept;
66
+ const target = opts.userGlobs.some((pattern) => matchesGlob(relative, pattern))
67
+ ? hidden
68
+ : kept;
67
69
  target.push(join(opts.root, relative));
68
70
  }
69
71
  return { kept: kept.sort(), hidden: hidden.sort() };
@@ -81,7 +83,7 @@ export class ArtifactScanner extends BaseHelper {
81
83
  }
82
84
  const exportedNames = this.collectExportClauseNames({ source });
83
85
  const found = [];
84
- ts.forEachChild(source, node => {
86
+ ts.forEachChild(source, (node) => {
85
87
  if (!ts.isClassDeclaration(node) || !node.name) {
86
88
  return;
87
89
  }
@@ -101,7 +103,7 @@ export class ArtifactScanner extends BaseHelper {
101
103
  });
102
104
  }
103
105
  const modifiers = ts.getModifiers(node) ?? [];
104
- const has = (kind) => modifiers.some(m => m.kind === kind);
106
+ const has = (kind) => modifiers.some((m) => m.kind === kind);
105
107
  const isNamedExport = (has(ts.SyntaxKind.ExportKeyword) && !has(ts.SyntaxKind.DefaultKeyword)) ||
106
108
  exportedNames.has(className);
107
109
  const isAbstract = has(ts.SyntaxKind.AbstractKeyword);
@@ -241,9 +243,9 @@ export class ArtifactScanner extends BaseHelper {
241
243
  }
242
244
  asArtifactType(opts) {
243
245
  const { raw } = opts;
244
- return ArtifactStereotypes.EMIT_ORDER.map(entry => entry.type)
246
+ return ArtifactStereotypes.EMIT_ORDER.map((entry) => entry.type)
245
247
  .concat(ArtifactTypes.MODEL)
246
- .find(type => type === raw);
248
+ .find((type) => type === raw);
247
249
  }
248
250
  }
249
251
  //# sourceMappingURL=scanner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/generator/scanner.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseHelper, getError } from '@venizia/ignis-helpers';\nimport { globSync, readFileSync } from 'node:fs';\nimport { join, matchesGlob, resolve } from 'node:path';\nimport ts from 'typescript';\nimport {\n ArtifactStereotypes,\n ArtifactTypes,\n ScanSkipReasons,\n type IScanOptions,\n type IScanReport,\n type IScanSkipped,\n type IScannedArtifact,\n type TArtifactType,\n} from './common';\nimport { StereotypeReexportResolver } from './reexport';\n\n/** Finds exported classes carrying a stereotype decorator by reading the source, never by running it. */\nexport class ArtifactScanner extends BaseHelper {\n private static instance?: ArtifactScanner;\n\n private constructor() {\n super({ scope: ArtifactScanner.name });\n }\n\n static getInstance(): ArtifactScanner {\n return (this.instance ??= new ArtifactScanner());\n }\n\n scan(opts: IScanOptions): IScannedArtifact[] {\n return this.scanWithReport(opts).artifacts;\n }\n\n /** `scan` plus the decorated classes a caller's own `ignore` pattern hid - the generator prints them so a stale pattern cannot drop an artifact in silence. */\n scanWithReport(opts: IScanOptions): IScanReport {\n const root = resolve(opts.root);\n const { kept, hidden } = this.partitionSourceFiles({\n root,\n defaultGlobs: ArtifactStereotypes.DEFAULT_IGNORE,\n userGlobs: opts.ignore ?? [],\n });\n const sourceModules = new Set(opts.sourceModules);\n const resolver = opts.followReexports\n ? new StereotypeReexportResolver({ root, sourceModules })\n : undefined;\n const skipped: IScanSkipped[] = [];\n\n const artifacts = this.sortArtifacts(\n kept.flatMap(filePath => this.scanFile({ filePath, sourceModules, resolver, skipped })),\n );\n const ignored = this.sortArtifacts(\n hidden.flatMap(filePath => this.scanHiddenFile({ filePath, sourceModules, resolver })),\n );\n for (const artifact of ignored) {\n skipped.push({\n className: artifact.className,\n filePath: artifact.filePath,\n reason: ScanSkipReasons.IGNORED,\n });\n }\n\n return { artifacts, ignored, skipped };\n }\n\n /** A hidden file is only reported on, never a reason to fail: a scan error becomes one warning and the file contributes nothing. */\n private scanHiddenFile(opts: {\n filePath: string;\n sourceModules: Set<string>;\n resolver?: StereotypeReexportResolver;\n }): IScannedArtifact[] {\n try {\n return this.scanFile({ ...opts, isHidden: true });\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n this.logger.for('scanHiddenFile').warn('Skipped hidden file %s | %s', opts.filePath, reason);\n return [];\n }\n }\n\n private sortArtifacts(artifacts: IScannedArtifact[]): IScannedArtifact[] {\n return artifacts.sort(\n (a, b) => a.type.localeCompare(b.type) || a.className.localeCompare(b.className),\n );\n }\n\n /** `kept` feeds the index; `hidden` is what only a user pattern excluded (a default pattern wins, so tests and generated files are never reported). */\n private partitionSourceFiles(opts: {\n root: string;\n defaultGlobs: ReadonlyArray<string>;\n userGlobs: ReadonlyArray<string>;\n }): { kept: string[]; hidden: string[] } {\n const kept: string[] = [];\n const hidden: string[] = [];\n\n const sources = globSync(ArtifactStereotypes.SOURCE_GLOB, { cwd: opts.root });\n for (const relative of sources) {\n if (\n relative.endsWith('.d.ts') ||\n opts.defaultGlobs.some(pattern => matchesGlob(relative, pattern))\n ) {\n continue;\n }\n const target = opts.userGlobs.some(pattern => matchesGlob(relative, pattern)) ? hidden : kept;\n target.push(join(opts.root, relative));\n }\n\n return { kept: kept.sort(), hidden: hidden.sort() };\n }\n\n private scanFile(opts: {\n filePath: string;\n sourceModules: Set<string>;\n resolver?: StereotypeReexportResolver;\n skipped?: IScanSkipped[];\n isHidden?: boolean;\n }): IScannedArtifact[] {\n const { filePath, sourceModules, resolver, skipped, isHidden = false } = opts;\n const source = ts.createSourceFile(\n filePath,\n readFileSync(filePath, 'utf8'),\n ts.ScriptTarget.Latest,\n true,\n );\n\n const stereotypeByLocalName = this.collectStereotypeImports({\n source,\n sourceModules,\n resolver,\n });\n if (stereotypeByLocalName.size === 0) {\n return [];\n }\n\n const exportedNames = this.collectExportClauseNames({ source });\n const found: IScannedArtifact[] = [];\n\n ts.forEachChild(source, node => {\n if (!ts.isClassDeclaration(node) || !node.name) {\n return;\n }\n\n const className = node.name.text;\n const types = this.artifactTypesOf({\n node,\n stereotypeByLocalName,\n filePath,\n className,\n });\n if (types.length === 0) {\n return;\n }\n if (types.length > 1) {\n throw getError({\n message: `[ArtifactScanner] ${filePath} | class ${className} carries ${types.length} stereotypes (${types.join(', ')}) - one class is one artifact`,\n });\n }\n\n const modifiers = ts.getModifiers(node) ?? [];\n const has = (kind: ts.SyntaxKind): boolean => modifiers.some(m => m.kind === kind);\n const isNamedExport =\n (has(ts.SyntaxKind.ExportKeyword) && !has(ts.SyntaxKind.DefaultKeyword)) ||\n exportedNames.has(className);\n const isAbstract = has(ts.SyntaxKind.AbstractKeyword);\n\n if (!isNamedExport || isAbstract) {\n if (!isHidden) {\n skipped?.push({\n className,\n filePath,\n reason: isAbstract ? ScanSkipReasons.ABSTRACT : ScanSkipReasons.NOT_EXPORTED,\n });\n this.logger\n .for('scanFile')\n .warn(\n 'Skipped %s in %s | %s',\n className,\n filePath,\n isAbstract ? 'abstract' : 'not a named export',\n );\n }\n return;\n }\n\n found.push({ className, filePath, type: types[0] });\n });\n\n return found;\n }\n\n /** local identifier -> stereotype name, for named imports from an IGNIS module or a caller-named source module (aliases resolved). */\n private collectStereotypeImports(opts: {\n source: ts.SourceFile;\n sourceModules: Set<string>;\n resolver?: StereotypeReexportResolver;\n }): Map<string, string> {\n const result = new Map<string, string>();\n // Only a name a class actually wears as a decorator is worth following through re-exports.\n const decoratorNames = opts.resolver\n ? this.collectClassDecoratorNames({ source: opts.source })\n : new Set<string>();\n\n for (const statement of opts.source.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {\n continue;\n }\n const specifier = statement.moduleSpecifier.text;\n const isSourceModule =\n ArtifactStereotypes.SOURCE_MODULES.test(specifier) || opts.sourceModules.has(specifier);\n if (!isSourceModule && !opts.resolver) {\n continue;\n }\n\n const bindings = statement.importClause?.namedBindings;\n if (!bindings || !ts.isNamedImports(bindings)) {\n continue;\n }\n\n for (const element of bindings.elements) {\n const name = (element.propertyName ?? element.name).text;\n if (!isSourceModule && !decoratorNames.has(element.name.text)) {\n continue;\n }\n const imported = isSourceModule\n ? name\n : opts.resolver?.originOf({ fromFile: opts.source.fileName, specifier, name });\n if (!imported) {\n continue;\n }\n const isStereotype =\n imported in ArtifactStereotypes.BY_DECORATOR ||\n imported === ArtifactStereotypes.ROOT_DECORATOR;\n if (isStereotype) {\n result.set(element.name.text, imported);\n }\n }\n }\n\n return result;\n }\n\n /** The identifiers called as decorators on the file's top-level classes (`@service()`, `@kit.service()` is not followed). */\n private collectClassDecoratorNames(opts: { source: ts.SourceFile }): Set<string> {\n const names = new Set<string>();\n for (const statement of opts.source.statements) {\n if (!ts.isClassDeclaration(statement)) {\n continue;\n }\n for (const decorator of ts.getDecorators(statement) ?? []) {\n const expression = decorator.expression;\n if (ts.isCallExpression(expression) && ts.isIdentifier(expression.expression)) {\n names.add(expression.expression.text);\n }\n }\n }\n return names;\n }\n\n private collectExportClauseNames(opts: { source: ts.SourceFile }): Set<string> {\n const names = new Set<string>();\n\n for (const statement of opts.source.statements) {\n if (\n ts.isExportDeclaration(statement) &&\n statement.exportClause &&\n ts.isNamedExports(statement.exportClause)\n ) {\n for (const element of statement.exportClause.elements) {\n names.add((element.propertyName ?? element.name).text);\n }\n }\n }\n\n return names;\n }\n\n private artifactTypesOf(opts: {\n node: ts.ClassDeclaration;\n stereotypeByLocalName: Map<string, string>;\n filePath: string;\n className: string;\n }): TArtifactType[] {\n const { node, stereotypeByLocalName, filePath, className } = opts;\n const types: TArtifactType[] = [];\n\n const decorators = ts.getDecorators(node) ?? [];\n for (const decorator of decorators) {\n const expression = decorator.expression;\n if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression)) {\n continue;\n }\n\n const stereotype = stereotypeByLocalName.get(expression.expression.text);\n if (!stereotype) {\n continue;\n }\n if (stereotype !== ArtifactStereotypes.ROOT_DECORATOR) {\n types.push(ArtifactStereotypes.BY_DECORATOR[stereotype]);\n continue;\n }\n\n const type = this.typeOfInjectableCall({ call: expression });\n if (!type) {\n this.logger\n .for('artifactTypesOf')\n .warn(\n 'Skipped %s in %s | @injectable type is not a literal or ArtifactTypes.<NAME>',\n className,\n filePath,\n );\n continue;\n }\n types.push(type);\n }\n\n return types;\n }\n\n private typeOfInjectableCall(opts: { call: ts.CallExpression }): TArtifactType | undefined {\n const [argument] = opts.call.arguments;\n if (!argument || !ts.isObjectLiteralExpression(argument)) {\n return undefined;\n }\n\n const property = argument.properties.find(\n (entry): entry is ts.PropertyAssignment =>\n ts.isPropertyAssignment(entry) && ts.isIdentifier(entry.name) && entry.name.text === 'type',\n );\n if (!property) {\n return undefined;\n }\n\n const value = property.initializer;\n if (ts.isStringLiteral(value)) {\n return this.asArtifactType({ raw: value.text });\n }\n if (\n ts.isPropertyAccessExpression(value) &&\n ts.isIdentifier(value.expression) &&\n value.expression.text === 'ArtifactTypes'\n ) {\n return this.asArtifactType({ raw: value.name.text.toLowerCase() });\n }\n\n return undefined;\n }\n\n private asArtifactType(opts: { raw: string }): TArtifactType | undefined {\n const { raw } = opts;\n return ArtifactStereotypes.EMIT_ORDER.map(entry => entry.type)\n .concat(ArtifactTypes.MODEL)\n .find(type => type === raw);\n }\n}\n"]}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/generator/scanner.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseHelper, getError } from '@venizia/ignis-helpers';\nimport { globSync, readFileSync } from 'node:fs';\nimport { join, matchesGlob, resolve } from 'node:path';\nimport ts from 'typescript';\nimport {\n ArtifactStereotypes,\n ArtifactTypes,\n ScanSkipReasons,\n type IScanOptions,\n type IScanReport,\n type IScanSkipped,\n type IScannedArtifact,\n type TArtifactType,\n} from './common';\nimport { StereotypeReexportResolver } from './reexport';\n\n/** Finds exported classes carrying a stereotype decorator by reading the source, never by running it. */\nexport class ArtifactScanner extends BaseHelper {\n private static instance?: ArtifactScanner;\n\n private constructor() {\n super({ scope: ArtifactScanner.name });\n }\n\n static getInstance(): ArtifactScanner {\n return (this.instance ??= new ArtifactScanner());\n }\n\n scan(opts: IScanOptions): IScannedArtifact[] {\n return this.scanWithReport(opts).artifacts;\n }\n\n /** `scan` plus the decorated classes a caller's own `ignore` pattern hid - the generator prints them so a stale pattern cannot drop an artifact in silence. */\n scanWithReport(opts: IScanOptions): IScanReport {\n const root = resolve(opts.root);\n const { kept, hidden } = this.partitionSourceFiles({\n root,\n defaultGlobs: ArtifactStereotypes.DEFAULT_IGNORE,\n userGlobs: opts.ignore ?? [],\n });\n const sourceModules = new Set(opts.sourceModules);\n const resolver = opts.followReexports\n ? new StereotypeReexportResolver({ root, sourceModules })\n : undefined;\n const skipped: IScanSkipped[] = [];\n\n const artifacts = this.sortArtifacts(\n kept.flatMap((filePath) => this.scanFile({ filePath, sourceModules, resolver, skipped })),\n );\n const ignored = this.sortArtifacts(\n hidden.flatMap((filePath) => this.scanHiddenFile({ filePath, sourceModules, resolver })),\n );\n for (const artifact of ignored) {\n skipped.push({\n className: artifact.className,\n filePath: artifact.filePath,\n reason: ScanSkipReasons.IGNORED,\n });\n }\n\n return { artifacts, ignored, skipped };\n }\n\n /** A hidden file is only reported on, never a reason to fail: a scan error becomes one warning and the file contributes nothing. */\n private scanHiddenFile(opts: {\n filePath: string;\n sourceModules: Set<string>;\n resolver?: StereotypeReexportResolver;\n }): IScannedArtifact[] {\n try {\n return this.scanFile({ ...opts, isHidden: true });\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n this.logger.for('scanHiddenFile').warn('Skipped hidden file %s | %s', opts.filePath, reason);\n return [];\n }\n }\n\n private sortArtifacts(artifacts: IScannedArtifact[]): IScannedArtifact[] {\n return artifacts.sort(\n (a, b) => a.type.localeCompare(b.type) || a.className.localeCompare(b.className),\n );\n }\n\n /** `kept` feeds the index; `hidden` is what only a user pattern excluded (a default pattern wins, so tests and generated files are never reported). */\n private partitionSourceFiles(opts: {\n root: string;\n defaultGlobs: ReadonlyArray<string>;\n userGlobs: ReadonlyArray<string>;\n }): { kept: string[]; hidden: string[] } {\n const kept: string[] = [];\n const hidden: string[] = [];\n\n const sources = globSync(ArtifactStereotypes.SOURCE_GLOB, { cwd: opts.root });\n for (const relative of sources) {\n if (\n relative.endsWith('.d.ts') ||\n opts.defaultGlobs.some((pattern) => matchesGlob(relative, pattern))\n ) {\n continue;\n }\n const target = opts.userGlobs.some((pattern) => matchesGlob(relative, pattern))\n ? hidden\n : kept;\n target.push(join(opts.root, relative));\n }\n\n return { kept: kept.sort(), hidden: hidden.sort() };\n }\n\n private scanFile(opts: {\n filePath: string;\n sourceModules: Set<string>;\n resolver?: StereotypeReexportResolver;\n skipped?: IScanSkipped[];\n isHidden?: boolean;\n }): IScannedArtifact[] {\n const { filePath, sourceModules, resolver, skipped, isHidden = false } = opts;\n const source = ts.createSourceFile(\n filePath,\n readFileSync(filePath, 'utf8'),\n ts.ScriptTarget.Latest,\n true,\n );\n\n const stereotypeByLocalName = this.collectStereotypeImports({\n source,\n sourceModules,\n resolver,\n });\n if (stereotypeByLocalName.size === 0) {\n return [];\n }\n\n const exportedNames = this.collectExportClauseNames({ source });\n const found: IScannedArtifact[] = [];\n\n ts.forEachChild(source, (node) => {\n if (!ts.isClassDeclaration(node) || !node.name) {\n return;\n }\n\n const className = node.name.text;\n const types = this.artifactTypesOf({\n node,\n stereotypeByLocalName,\n filePath,\n className,\n });\n if (types.length === 0) {\n return;\n }\n if (types.length > 1) {\n throw getError({\n message: `[ArtifactScanner] ${filePath} | class ${className} carries ${types.length} stereotypes (${types.join(', ')}) - one class is one artifact`,\n });\n }\n\n const modifiers = ts.getModifiers(node) ?? [];\n const has = (kind: ts.SyntaxKind): boolean => modifiers.some((m) => m.kind === kind);\n const isNamedExport =\n (has(ts.SyntaxKind.ExportKeyword) && !has(ts.SyntaxKind.DefaultKeyword)) ||\n exportedNames.has(className);\n const isAbstract = has(ts.SyntaxKind.AbstractKeyword);\n\n if (!isNamedExport || isAbstract) {\n if (!isHidden) {\n skipped?.push({\n className,\n filePath,\n reason: isAbstract ? ScanSkipReasons.ABSTRACT : ScanSkipReasons.NOT_EXPORTED,\n });\n this.logger\n .for('scanFile')\n .warn(\n 'Skipped %s in %s | %s',\n className,\n filePath,\n isAbstract ? 'abstract' : 'not a named export',\n );\n }\n return;\n }\n\n found.push({ className, filePath, type: types[0] });\n });\n\n return found;\n }\n\n /** local identifier -> stereotype name, for named imports from an IGNIS module or a caller-named source module (aliases resolved). */\n private collectStereotypeImports(opts: {\n source: ts.SourceFile;\n sourceModules: Set<string>;\n resolver?: StereotypeReexportResolver;\n }): Map<string, string> {\n const result = new Map<string, string>();\n // Only a name a class actually wears as a decorator is worth following through re-exports.\n const decoratorNames = opts.resolver\n ? this.collectClassDecoratorNames({ source: opts.source })\n : new Set<string>();\n\n for (const statement of opts.source.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {\n continue;\n }\n const specifier = statement.moduleSpecifier.text;\n const isSourceModule =\n ArtifactStereotypes.SOURCE_MODULES.test(specifier) || opts.sourceModules.has(specifier);\n if (!isSourceModule && !opts.resolver) {\n continue;\n }\n\n const bindings = statement.importClause?.namedBindings;\n if (!bindings || !ts.isNamedImports(bindings)) {\n continue;\n }\n\n for (const element of bindings.elements) {\n const name = (element.propertyName ?? element.name).text;\n if (!isSourceModule && !decoratorNames.has(element.name.text)) {\n continue;\n }\n const imported = isSourceModule\n ? name\n : opts.resolver?.originOf({ fromFile: opts.source.fileName, specifier, name });\n if (!imported) {\n continue;\n }\n const isStereotype =\n imported in ArtifactStereotypes.BY_DECORATOR ||\n imported === ArtifactStereotypes.ROOT_DECORATOR;\n if (isStereotype) {\n result.set(element.name.text, imported);\n }\n }\n }\n\n return result;\n }\n\n /** The identifiers called as decorators on the file's top-level classes (`@service()`, `@kit.service()` is not followed). */\n private collectClassDecoratorNames(opts: { source: ts.SourceFile }): Set<string> {\n const names = new Set<string>();\n for (const statement of opts.source.statements) {\n if (!ts.isClassDeclaration(statement)) {\n continue;\n }\n for (const decorator of ts.getDecorators(statement) ?? []) {\n const expression = decorator.expression;\n if (ts.isCallExpression(expression) && ts.isIdentifier(expression.expression)) {\n names.add(expression.expression.text);\n }\n }\n }\n return names;\n }\n\n private collectExportClauseNames(opts: { source: ts.SourceFile }): Set<string> {\n const names = new Set<string>();\n\n for (const statement of opts.source.statements) {\n if (\n ts.isExportDeclaration(statement) &&\n statement.exportClause &&\n ts.isNamedExports(statement.exportClause)\n ) {\n for (const element of statement.exportClause.elements) {\n names.add((element.propertyName ?? element.name).text);\n }\n }\n }\n\n return names;\n }\n\n private artifactTypesOf(opts: {\n node: ts.ClassDeclaration;\n stereotypeByLocalName: Map<string, string>;\n filePath: string;\n className: string;\n }): TArtifactType[] {\n const { node, stereotypeByLocalName, filePath, className } = opts;\n const types: TArtifactType[] = [];\n\n const decorators = ts.getDecorators(node) ?? [];\n for (const decorator of decorators) {\n const expression = decorator.expression;\n if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression)) {\n continue;\n }\n\n const stereotype = stereotypeByLocalName.get(expression.expression.text);\n if (!stereotype) {\n continue;\n }\n if (stereotype !== ArtifactStereotypes.ROOT_DECORATOR) {\n types.push(ArtifactStereotypes.BY_DECORATOR[stereotype]);\n continue;\n }\n\n const type = this.typeOfInjectableCall({ call: expression });\n if (!type) {\n this.logger\n .for('artifactTypesOf')\n .warn(\n 'Skipped %s in %s | @injectable type is not a literal or ArtifactTypes.<NAME>',\n className,\n filePath,\n );\n continue;\n }\n types.push(type);\n }\n\n return types;\n }\n\n private typeOfInjectableCall(opts: { call: ts.CallExpression }): TArtifactType | undefined {\n const [argument] = opts.call.arguments;\n if (!argument || !ts.isObjectLiteralExpression(argument)) {\n return undefined;\n }\n\n const property = argument.properties.find(\n (entry): entry is ts.PropertyAssignment =>\n ts.isPropertyAssignment(entry) && ts.isIdentifier(entry.name) && entry.name.text === 'type',\n );\n if (!property) {\n return undefined;\n }\n\n const value = property.initializer;\n if (ts.isStringLiteral(value)) {\n return this.asArtifactType({ raw: value.text });\n }\n if (\n ts.isPropertyAccessExpression(value) &&\n ts.isIdentifier(value.expression) &&\n value.expression.text === 'ArtifactTypes'\n ) {\n return this.asArtifactType({ raw: value.name.text.toLowerCase() });\n }\n\n return undefined;\n }\n\n private asArtifactType(opts: { raw: string }): TArtifactType | undefined {\n const { raw } = opts;\n return ArtifactStereotypes.EMIT_ORDER.map((entry) => entry.type)\n .concat(ArtifactTypes.MODEL)\n .find((type) => type === raw);\n }\n}\n"]}
@@ -24,13 +24,13 @@ export class IgnisArtifactsVitePlugin {
24
24
  enforce: 'pre',
25
25
  // Pre-bundling would hide `auto` inside a dependency chunk, out of reach of `load`.
26
26
  config: () => ({ optimizeDeps: { exclude: ['@venizia/ignis-boot'] } }),
27
- configResolved: config => {
27
+ configResolved: (config) => {
28
28
  root ||= ArtifactSources.packageSource({ from: config.root });
29
29
  groupFiles = new Set(IgnisArtifactsPlugin.groupDefinitionFiles({ root }));
30
30
  classesByFile = IgnisArtifactsPlugin.pinnedClasses({ root, groupFiles: [...groupFiles] });
31
31
  },
32
- resolveId: id => id === IgnisArtifactsPlugin.VIRTUAL ? IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL : undefined,
33
- load: id => {
32
+ resolveId: (id) => id === IgnisArtifactsPlugin.VIRTUAL ? IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL : undefined,
33
+ load: (id) => {
34
34
  if (id === IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL) {
35
35
  return IgnisArtifactsPlugin.render({ root });
36
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/vite/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAajD,mWAAmW;AACnW,MAAM,OAAO,wBAAwB;aACnB,qBAAgB,GAAG,KAAK,oBAAoB,CAAC,OAAO,EAAE,CAAC;IAEvE;QACE,eAAe,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,6FAA6F;IAC7F,wGAAwG;IACxG,MAAM,CAAC,UAAU,CAAC,IAAoB;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,OAA0B,EAAE;QACxC,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,IAAI,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QACnC,IAAI,aAAa,GAAG,IAAI,GAAG,EAAuB,CAAC;QACnD,MAAM,UAAU,GAAG,YAAY,oBAAoB,CAAC,WAAW,YAAY,oBAAoB,CAAC,OAAO,0GAA0G,oBAAoB,CAAC,WAAW,QAAQ,CAAC;QAE1P,OAAO;YACL,IAAI,EAAE,oBAAoB,CAAC,IAAI;YAC/B,OAAO,EAAE,KAAK;YACd,oFAAoF;YACpF,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,EAAE,CAAC;YACtE,cAAc,EAAE,MAAM,CAAC,EAAE;gBACvB,IAAI,KAAK,eAAe,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9D,UAAU,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC1E,aAAa,GAAG,oBAAoB,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;YAC5F,CAAC;YACD,SAAS,EAAE,EAAE,CAAC,EAAE,CACd,EAAE,KAAK,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS;YAC7F,IAAI,EAAE,EAAE,CAAC,EAAE;gBACT,IAAI,EAAE,KAAK,wBAAwB,CAAC,gBAAgB,EAAE,CAAC;oBACrD,OAAO,oBAAoB,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/C,CAAC;gBACD,OAAO,oBAAoB,CAAC,WAAW,CAAC,IAAI,CAAC,wBAAwB,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACvF,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,SAAS,CAAC;YAChB,CAAC;YACD,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;gBAC5B,MAAM,EAAE,GAAG,wBAAwB,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACjE,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACzC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;oBACvC,OAAO,SAAS,CAAC;gBACnB,CAAC;gBACD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBAChC,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;oBACpE,CAAC,CAAC,IAAI,CAAC;gBACT,OAAO,UAAU;oBACf,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;oBACnF,CAAC,CAAC,OAAO,CAAC;YACd,CAAC;SACF,CAAC;IACJ,CAAC","sourcesContent":["import { resolve } from 'node:path';\nimport { ArtifactScanner } from '../generator';\nimport { IgnisArtifactsPlugin } from '../bun/plugin';\nimport { ArtifactSources } from '../bun/sources';\n\n/** The slice of Vite's plugin contract this plugin uses - typed here so `@venizia/ignis-boot` does not depend on `vite`. */\nexport interface IIgnisVitePlugin {\n name: string;\n enforce: 'pre';\n config: () => { optimizeDeps: { exclude: string[] } };\n configResolved: (config: { root: string }) => void;\n resolveId: (id: string) => string | undefined;\n load: (id: string) => string | undefined;\n transform: (code: string, id: string) => string | undefined;\n}\n\n/** `IgnisArtifactsPlugin` for Vite: serves `ignis:artifacts`, replaces `@venizia/ignis-boot/auto` with an eager import of it (a browser bundle is tree-shaken only when eager), inlines every `ArtifactGroup.define` / `application` call, and pins the name of every scanned class - binding keys are built from `Class.name`, and a minifier renames classes. */\nexport class IgnisArtifactsVitePlugin {\n static readonly RESOLVED_VIRTUAL = `\\0${IgnisArtifactsPlugin.VIRTUAL}`;\n\n static {\n ArtifactSources.useScanner({ scanner: ArtifactScanner.getInstance() });\n }\n\n /** `root`: the `src` to scan (default: the one beside the `package.json` of Vite's root). */\n /** The file a module id names: vite dev adds a query (`?v=<hash>`) to the id of a node_modules file. */\n static filePathOf(opts: { id: string }): string {\n const queryAt = opts.id.indexOf('?');\n return queryAt === -1 ? opts.id : opts.id.slice(0, queryAt);\n }\n\n static create(opts: { root?: string } = {}): IIgnisVitePlugin {\n let root = opts.root ? resolve(opts.root) : '';\n let groupFiles = new Set<string>();\n let classesByFile = new Map<string, Set<string>>();\n const autoModule = `import { ${IgnisArtifactsPlugin.EXPORT_NAME} } from '${IgnisArtifactsPlugin.VIRTUAL}';\\nimport { AutoArtifactGroup } from './auto-group';\\nexport default new AutoArtifactGroup({ content: ${IgnisArtifactsPlugin.EXPORT_NAME} });\\n`;\n\n return {\n name: IgnisArtifactsPlugin.NAME,\n enforce: 'pre',\n // Pre-bundling would hide `auto` inside a dependency chunk, out of reach of `load`.\n config: () => ({ optimizeDeps: { exclude: ['@venizia/ignis-boot'] } }),\n configResolved: config => {\n root ||= ArtifactSources.packageSource({ from: config.root });\n groupFiles = new Set(IgnisArtifactsPlugin.groupDefinitionFiles({ root }));\n classesByFile = IgnisArtifactsPlugin.pinnedClasses({ root, groupFiles: [...groupFiles] });\n },\n resolveId: id =>\n id === IgnisArtifactsPlugin.VIRTUAL ? IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL : undefined,\n load: id => {\n if (id === IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL) {\n return IgnisArtifactsPlugin.render({ root });\n }\n return IgnisArtifactsPlugin.AUTO_MODULE.test(IgnisArtifactsVitePlugin.filePathOf({ id }))\n ? autoModule\n : undefined;\n },\n transform: (code, moduleId) => {\n const id = IgnisArtifactsVitePlugin.filePathOf({ id: moduleId });\n const classNames = classesByFile.get(id);\n if (!groupFiles.has(id) && !classNames) {\n return undefined;\n }\n const grouped = groupFiles.has(id)\n ? IgnisArtifactsPlugin.rewriteGroups({ filePath: id, source: code })\n : code;\n return classNames\n ? IgnisArtifactsPlugin.pinClassNames({ filePath: id, source: grouped, classNames })\n : grouped;\n },\n };\n }\n}\n"]}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/vite/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolve } from 'node:path';\nimport { ArtifactScanner } from '../generator';\nimport { IgnisArtifactsPlugin } from '../bun/plugin';\nimport { ArtifactSources } from '../bun/sources';\n\n/** The slice of Vite's plugin contract this plugin uses - typed here so `@venizia/ignis-boot` does not depend on `vite`. */\nexport interface IIgnisVitePlugin {\n name: string;\n enforce: 'pre';\n config: () => { optimizeDeps: { exclude: string[] } };\n configResolved: (config: { root: string }) => void;\n resolveId: (id: string) => string | undefined;\n load: (id: string) => string | undefined;\n transform: (code: string, id: string) => string | undefined;\n}\n\n/** `IgnisArtifactsPlugin` for Vite: serves `ignis:artifacts`, replaces `@venizia/ignis-boot/auto` with an eager import of it (a browser bundle is tree-shaken only when eager), inlines every `ArtifactGroup.define` / `application` call, and pins the name of every scanned class - binding keys are built from `Class.name`, and a minifier renames classes. */\nexport class IgnisArtifactsVitePlugin {\n static readonly RESOLVED_VIRTUAL = `\\0${IgnisArtifactsPlugin.VIRTUAL}`;\n\n static {\n ArtifactSources.useScanner({ scanner: ArtifactScanner.getInstance() });\n }\n\n /** `root`: the `src` to scan (default: the one beside the `package.json` of Vite's root). */\n /** The file a module id names: vite dev adds a query (`?v=<hash>`) to the id of a node_modules file. */\n static filePathOf(opts: { id: string }): string {\n const queryAt = opts.id.indexOf('?');\n return queryAt === -1 ? opts.id : opts.id.slice(0, queryAt);\n }\n\n static create(opts: { root?: string } = {}): IIgnisVitePlugin {\n let root = opts.root ? resolve(opts.root) : '';\n let groupFiles = new Set<string>();\n let classesByFile = new Map<string, Set<string>>();\n const autoModule = `import { ${IgnisArtifactsPlugin.EXPORT_NAME} } from '${IgnisArtifactsPlugin.VIRTUAL}';\\nimport { AutoArtifactGroup } from './auto-group';\\nexport default new AutoArtifactGroup({ content: ${IgnisArtifactsPlugin.EXPORT_NAME} });\\n`;\n\n return {\n name: IgnisArtifactsPlugin.NAME,\n enforce: 'pre',\n // Pre-bundling would hide `auto` inside a dependency chunk, out of reach of `load`.\n config: () => ({ optimizeDeps: { exclude: ['@venizia/ignis-boot'] } }),\n configResolved: (config) => {\n root ||= ArtifactSources.packageSource({ from: config.root });\n groupFiles = new Set(IgnisArtifactsPlugin.groupDefinitionFiles({ root }));\n classesByFile = IgnisArtifactsPlugin.pinnedClasses({ root, groupFiles: [...groupFiles] });\n },\n resolveId: (id) =>\n id === IgnisArtifactsPlugin.VIRTUAL ? IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL : undefined,\n load: (id) => {\n if (id === IgnisArtifactsVitePlugin.RESOLVED_VIRTUAL) {\n return IgnisArtifactsPlugin.render({ root });\n }\n return IgnisArtifactsPlugin.AUTO_MODULE.test(IgnisArtifactsVitePlugin.filePathOf({ id }))\n ? autoModule\n : undefined;\n },\n transform: (code, moduleId) => {\n const id = IgnisArtifactsVitePlugin.filePathOf({ id: moduleId });\n const classNames = classesByFile.get(id);\n if (!groupFiles.has(id) && !classNames) {\n return undefined;\n }\n const grouped = groupFiles.has(id)\n ? IgnisArtifactsPlugin.rewriteGroups({ filePath: id, source: code })\n : code;\n return classNames\n ? IgnisArtifactsPlugin.pinClassNames({ filePath: id, source: grouped, classNames })\n : grouped;\n },\n };\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/ignis-boot",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Build-time artifact index generator for IGNIS applications: scans decorated classes with the TypeScript AST and emits one static registration file per package, so bun build --compile sees plain imports.",
5
5
  "keywords": [
6
6
  "artifact-index",
@@ -89,17 +89,17 @@
89
89
  "access": "public"
90
90
  },
91
91
  "scripts": {
92
- "force-update": "sh ../../scripts/force-update.sh",
92
+ "force-update": "sh ../../scripts/build/force-update.sh",
93
93
  "prepublishOnly": "make rebuild",
94
94
  "test": "bun test ./src"
95
95
  },
96
96
  "dependencies": {
97
- "@venizia/ignis-helpers": "0.4.0",
98
- "@venizia/ignis-inversion": "0.4.0"
97
+ "@venizia/ignis-helpers": "0.4.1",
98
+ "@venizia/ignis-inversion": "0.4.1"
99
99
  },
100
100
  "devDependencies": {
101
101
  "@types/bun": "^1.4.3",
102
- "@venizia/dev-configs": "0.4.0",
102
+ "@venizia/dev-configs": "0.4.1",
103
103
  "eslint": "^10.13.0",
104
104
  "oxlint": "1.89.0",
105
105
  "oxlint-tsgolint": "7.0.2004",