@venizia/ignis-boot 0.4.8-0 → 0.4.8-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Build-time tools for an IGNIS application: `ignis-artifacts` writes one static f
8
8
  bun add -d @venizia/ignis-boot typescript
9
9
  ```
10
10
 
11
- `typescript` 5 or 6 is a required peer: the scanner reads your source with the TypeScript compiler API. Both binaries run under Bun (they carry a `bun` shebang).
11
+ `typescript` 5 or 6 is a required peer: the scanner reads your source with the TypeScript compiler API. `ignis-artifacts` runs under Bun (it carries a `bun` shebang).
12
12
 
13
13
  ## Register your classes
14
14
 
@@ -71,17 +71,18 @@ The scanner reads source text and never imports a module. No decorator runs and
71
71
  ## `ignis-artifacts`
72
72
 
73
73
  ```
74
- ignis-artifacts <generate|check> [--root src] [--out src/generated/artifacts.ts] [--ignore a,b] [--export GeneratedArtifacts]
74
+ ignis-artifacts <generate|check> [--root src] [--out src/generated/artifacts.ts] [--ignore a,b] [--export GeneratedArtifacts] [--source-module <specifier>]...
75
75
  ```
76
76
 
77
77
  | Flag | Default | Meaning |
78
78
  |---|---|---|
79
- | `--root` | `src` | Directory to scan, recursively (`.ts` files, `.d.ts` skipped) |
79
+ | `--root` | `src` | Directory to scan, recursively (`.ts` and `.tsx` files, `.d.ts` skipped) |
80
80
  | `--out` | `src/generated/artifacts.ts` | Output file; import paths are relative to it |
81
81
  | `--ignore` | none | Comma-separated globs, relative to `--root`, added to the default list |
82
82
  | `--export` | `GeneratedArtifacts` | Name of the exported constant |
83
+ | `--source-module` | none | A module specifier, matched exactly, whose stereotype imports also count - a package that re-exports the decorators. Repeat the flag for several. Adds to `@venizia/ignis` and `@venizia/ignis-kernel` |
83
84
 
84
- The default ignore list always applies: `**/__tests__/**`, `**/*.test.ts`, `**/*.spec.ts`, `**/generated/**`. A decorated class hidden by one of your own `--ignore` patterns prints one `warning:` line on stderr.
85
+ The default ignore list always applies: `**/__tests__/**`, `**/*.test.{ts,tsx}`, `**/*.spec.{ts,tsx}`, `**/generated/**`. A decorated class hidden by one of your own `--ignore` patterns prints one `warning:` line on stderr.
85
86
 
86
87
  | Command | Effect | Exit code |
87
88
  |---|---|---|
@@ -95,7 +96,7 @@ A class lands in the index when all of these hold. The scanner logs a warning fo
95
96
 
96
97
  - It is a named export (`export class` or `export { Name }`), not `export default`.
97
98
  - It is not `abstract`.
98
- - It carries exactly one of `@configuration`, `@component`, `@controller`, `@service`, `@repository` or `@datasource`, imported by name from `@venizia/ignis` or `@venizia/ignis-kernel` (aliases resolved). `@injectable({ type })` counts when `type` is a string literal or `ArtifactTypes.<NAME>`.
99
+ - It carries exactly one of `@configuration`, `@component`, `@controller`, `@service`, `@repository` or `@datasource`, imported by name from `@venizia/ignis`, `@venizia/ignis-kernel` or a module named with `--source-module` (aliases resolved). `@injectable({ type })` counts when `type` is a string literal or `ArtifactTypes.<NAME>`.
99
100
 
100
101
  `@model` classes are recognized and never emitted - a repository registers its model. A decorator re-exported through your own wrapper module is not recognized. Two stereotypes on one class fail the scan.
101
102
 
@@ -140,9 +141,12 @@ The resolver reads each field from the environment first (first non-blank key wi
140
141
 
141
142
  | Subpath | What it gives | Extra peers |
142
143
  |---|---|---|
143
- | `@venizia/ignis-boot` | Everything from the two subpaths below | `typescript` |
144
+ | `@venizia/ignis-boot` | Everything from `/generator` and `/build-info` | `typescript` |
144
145
  | `@venizia/ignis-boot/generator` | `ArtifactIndexGenerator`, `ArtifactScanner`, `ArtifactIndexEmitter`, `ArtifactStereotypes`, `ArtifactTypes`, `ArtifactIndexFields` | `typescript` |
145
146
  | `@venizia/ignis-boot/build-info` | `BuildInfoStamp`, `BuildInfoResolver`, `BuildInfoEnvironmentKeys` | none |
147
+ | `@venizia/ignis-boot/bun` | `IgnisArtifactsPlugin` (a Bun plugin that serves the `ignis:artifacts` module for `Bun.build`), `AutoArtifactGroup`, `AutoArtifactsLoader`, `GroupArtifactsResolver` | `typescript` (Bun only) |
148
+ | `@venizia/ignis-boot/auto` | Default export `AutoArtifacts`: the application's decorated classes, found by the scanner at start. Pass it in `configs.artifacts`. Importing it has a side effect, so the package marks it in `sideEffects` | `typescript` (Bun only) |
149
+ | `@venizia/ignis-boot/vite` | `IgnisArtifactsVitePlugin`: the same `ignis:artifacts` module for Vite, and it replaces `/auto` with an eager import so a browser bundle can be tree-shaken | `typescript` |
146
150
 
147
151
  | Binary | File |
148
152
  |---|---|
@@ -158,7 +162,7 @@ const { isFresh } = ArtifactIndexGenerator.check({ root: 'src', out: 'src/genera
158
162
 
159
163
  ## Where it sits
160
164
 
161
- `dev-configs -> inversion -> {filter, helpers} -> {boot, kernel} -> connectors -> {core-worker, core-server}`. Boot depends on `@venizia/ignis-helpers` only; no IGNIS package depends on boot, so the application declares it.
165
+ `dev-configs -> inversion -> {filter, helpers} -> {boot, kernel} -> connectors -> {core-worker, core-server}`. Boot depends on `@venizia/ignis-helpers` and `@venizia/ignis-inversion`; no IGNIS package depends on boot, so the application declares it.
162
166
 
163
167
  The generated index replaces a run-time scan of the file system at startup.
164
168
 
@@ -11,6 +11,7 @@ export declare class ArtifactTypes {
11
11
  static readonly SCHEME_SET: Set<string>;
12
12
  static isValid(value: string): boolean;
13
13
  }
14
+ /** One of the `ArtifactTypes` values. */
14
15
  export type TArtifactType = TConstValue<typeof ArtifactTypes>;
15
16
  /** Mirrors the kernel's `ArtifactIndexFields` - the keys of the object the emitter writes and `registerArtifacts` reads. */
16
17
  export declare class ArtifactIndexFields {
@@ -23,7 +24,9 @@ export declare class ArtifactIndexFields {
23
24
  static readonly SCHEME_SET: Set<string>;
24
25
  static isValid(value: string): boolean;
25
26
  }
27
+ /** One of the `ArtifactIndexFields` values. */
26
28
  export type TArtifactIndexField = TConstValue<typeof ArtifactIndexFields>;
29
+ /** How the scanner recognises a decorated class: the source glob, decorator-to-type map, default ignore patterns and the emit order. */
27
30
  export declare class ArtifactStereotypes {
28
31
  /** The source files the scanner reads: TypeScript, with or without JSX. */
29
32
  static readonly SOURCE_GLOB = "**/*.{ts,tsx}";
@@ -55,5 +58,6 @@ export declare class ScanSkipReasons {
55
58
  static readonly SCHEME_SET: Set<string>;
56
59
  static isValid(value: string): boolean;
57
60
  }
61
+ /** One of the `ScanSkipReasons` values. */
58
62
  export type TScanSkipReason = TConstValue<typeof ScanSkipReasons>;
59
63
  //# sourceMappingURL=constants.d.ts.map
@@ -40,6 +40,7 @@ export class ArtifactIndexFields {
40
40
  return this.SCHEME_SET.has(value);
41
41
  }
42
42
  }
43
+ /** How the scanner recognises a decorated class: the source glob, decorator-to-type map, default ignore patterns and the emit order. */
43
44
  export class ArtifactStereotypes {
44
45
  /** The source files the scanner reads: TypeScript, with or without JSX. */
45
46
  static { this.SOURCE_GLOB = '**/*.{ts,tsx}'; }
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/generator/common/constants.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TConstValue } from '@venizia/ignis-helpers';\n\n/** Mirrors the kernel's `ArtifactTypes` values; boot must not depend on kernel (`{boot, kernel} -> core` in the build chain). */\nexport class ArtifactTypes {\n static readonly CONFIGURATION = 'configuration';\n static readonly COMPONENT = 'component';\n static readonly CONTROLLER = 'controller';\n static readonly SERVICE = 'service';\n static readonly REPOSITORY = 'repository';\n static readonly DATASOURCE = 'datasource';\n static readonly MODEL = 'model';\n\n static readonly SCHEME_SET = new Set<string>([\n this.CONFIGURATION,\n this.COMPONENT,\n this.CONTROLLER,\n this.SERVICE,\n this.REPOSITORY,\n this.DATASOURCE,\n this.MODEL,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\nexport type TArtifactType = TConstValue<typeof ArtifactTypes>;\n\n/** Mirrors the kernel's `ArtifactIndexFields` - the keys of the object the emitter writes and `registerArtifacts` reads. */\nexport class ArtifactIndexFields {\n static readonly CONFIGURATIONS = 'configurations';\n static readonly DATA_SOURCES = 'dataSources';\n static readonly COMPONENTS = 'components';\n static readonly REPOSITORIES = 'repositories';\n static readonly SERVICES = 'services';\n static readonly CONTROLLERS = 'controllers';\n\n static readonly SCHEME_SET = new Set<string>([\n this.CONFIGURATIONS,\n this.DATA_SOURCES,\n this.COMPONENTS,\n this.REPOSITORIES,\n this.SERVICES,\n this.CONTROLLERS,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\nexport type TArtifactIndexField = TConstValue<typeof ArtifactIndexFields>;\n\nexport class ArtifactStereotypes {\n /** The source files the scanner reads: TypeScript, with or without JSX. */\n static readonly SOURCE_GLOB = '**/*.{ts,tsx}';\n /** The extension of a source file - stripped for an import specifier, replaced by `.js` for its compiled copy. */\n static readonly SOURCE_EXTENSION = /\\.tsx?$/;\n /** Decorator name as imported from `@venizia/ignis` or `@venizia/ignis-kernel` -> artifact type. */\n static readonly BY_DECORATOR: Readonly<Record<string, TArtifactType>> = {\n configuration: ArtifactTypes.CONFIGURATION,\n component: ArtifactTypes.COMPONENT,\n controller: ArtifactTypes.CONTROLLER,\n service: ArtifactTypes.SERVICE,\n repository: ArtifactTypes.REPOSITORY,\n datasource: ArtifactTypes.DATASOURCE,\n model: ArtifactTypes.MODEL,\n };\n\n static readonly ROOT_DECORATOR = 'injectable';\n\n static readonly SCHEME_SET = new Set<string>(Object.values(ArtifactStereotypes.BY_DECORATOR));\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n\n static readonly SOURCE_MODULES = /^@venizia\\/ignis(?:-kernel)?(?:\\/.+)?$/;\n\n static readonly DEFAULT_IGNORE = [\n '**/__tests__/**',\n '**/*.test.{ts,tsx}',\n '**/*.spec.{ts,tsx}',\n '**/generated/**',\n ];\n\n /**\n * The kernel's `registerArtifacts` order; `model` is never emitted. Configurations come first:\n * `registerConfigurations` runs before the datasource and component sweeps, so a `@configuration`\n * can shape what they read. The kernel sorts them among themselves by their `after` declarations\n * at boot, so the order within the field does not matter here.\n */\n static readonly EMIT_ORDER: ReadonlyArray<{ type: TArtifactType; field: TArtifactIndexField }> = [\n { type: ArtifactTypes.CONFIGURATION, field: ArtifactIndexFields.CONFIGURATIONS },\n { type: ArtifactTypes.DATASOURCE, field: ArtifactIndexFields.DATA_SOURCES },\n { type: ArtifactTypes.COMPONENT, field: ArtifactIndexFields.COMPONENTS },\n { type: ArtifactTypes.REPOSITORY, field: ArtifactIndexFields.REPOSITORIES },\n { type: ArtifactTypes.SERVICE, field: ArtifactIndexFields.SERVICES },\n { type: ArtifactTypes.CONTROLLER, field: ArtifactIndexFields.CONTROLLERS },\n ];\n}\n\n/** Why a decorated class was left out of the index - reported, never silent. */\nexport class ScanSkipReasons {\n static readonly ABSTRACT = 'abstract';\n static readonly NOT_EXPORTED = 'not-exported';\n static readonly IGNORED = 'ignored';\n\n static readonly SCHEME_SET = new Set<string>([this.ABSTRACT, this.NOT_EXPORTED, this.IGNORED]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\nexport type TScanSkipReason = TConstValue<typeof ScanSkipReasons>;\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/generator/common/constants.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TConstValue } from '@venizia/ignis-helpers';\n\n/** Mirrors the kernel's `ArtifactTypes` values; boot must not depend on kernel (`{boot, kernel} -> core` in the build chain). */\nexport class ArtifactTypes {\n static readonly CONFIGURATION = 'configuration';\n static readonly COMPONENT = 'component';\n static readonly CONTROLLER = 'controller';\n static readonly SERVICE = 'service';\n static readonly REPOSITORY = 'repository';\n static readonly DATASOURCE = 'datasource';\n static readonly MODEL = 'model';\n\n static readonly SCHEME_SET = new Set<string>([\n this.CONFIGURATION,\n this.COMPONENT,\n this.CONTROLLER,\n this.SERVICE,\n this.REPOSITORY,\n this.DATASOURCE,\n this.MODEL,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\n/** One of the `ArtifactTypes` values. */\nexport type TArtifactType = TConstValue<typeof ArtifactTypes>;\n\n/** Mirrors the kernel's `ArtifactIndexFields` - the keys of the object the emitter writes and `registerArtifacts` reads. */\nexport class ArtifactIndexFields {\n static readonly CONFIGURATIONS = 'configurations';\n static readonly DATA_SOURCES = 'dataSources';\n static readonly COMPONENTS = 'components';\n static readonly REPOSITORIES = 'repositories';\n static readonly SERVICES = 'services';\n static readonly CONTROLLERS = 'controllers';\n\n static readonly SCHEME_SET = new Set<string>([\n this.CONFIGURATIONS,\n this.DATA_SOURCES,\n this.COMPONENTS,\n this.REPOSITORIES,\n this.SERVICES,\n this.CONTROLLERS,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\n/** One of the `ArtifactIndexFields` values. */\nexport type TArtifactIndexField = TConstValue<typeof ArtifactIndexFields>;\n\n/** How the scanner recognises a decorated class: the source glob, decorator-to-type map, default ignore patterns and the emit order. */\nexport class ArtifactStereotypes {\n /** The source files the scanner reads: TypeScript, with or without JSX. */\n static readonly SOURCE_GLOB = '**/*.{ts,tsx}';\n /** The extension of a source file - stripped for an import specifier, replaced by `.js` for its compiled copy. */\n static readonly SOURCE_EXTENSION = /\\.tsx?$/;\n /** Decorator name as imported from `@venizia/ignis` or `@venizia/ignis-kernel` -> artifact type. */\n static readonly BY_DECORATOR: Readonly<Record<string, TArtifactType>> = {\n configuration: ArtifactTypes.CONFIGURATION,\n component: ArtifactTypes.COMPONENT,\n controller: ArtifactTypes.CONTROLLER,\n service: ArtifactTypes.SERVICE,\n repository: ArtifactTypes.REPOSITORY,\n datasource: ArtifactTypes.DATASOURCE,\n model: ArtifactTypes.MODEL,\n };\n\n static readonly ROOT_DECORATOR = 'injectable';\n\n static readonly SCHEME_SET = new Set<string>(Object.values(ArtifactStereotypes.BY_DECORATOR));\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n\n static readonly SOURCE_MODULES = /^@venizia\\/ignis(?:-kernel)?(?:\\/.+)?$/;\n\n static readonly DEFAULT_IGNORE = [\n '**/__tests__/**',\n '**/*.test.{ts,tsx}',\n '**/*.spec.{ts,tsx}',\n '**/generated/**',\n ];\n\n /**\n * The kernel's `registerArtifacts` order; `model` is never emitted. Configurations come first:\n * `registerConfigurations` runs before the datasource and component sweeps, so a `@configuration`\n * can shape what they read. The kernel sorts them among themselves by their `after` declarations\n * at boot, so the order within the field does not matter here.\n */\n static readonly EMIT_ORDER: ReadonlyArray<{ type: TArtifactType; field: TArtifactIndexField }> = [\n { type: ArtifactTypes.CONFIGURATION, field: ArtifactIndexFields.CONFIGURATIONS },\n { type: ArtifactTypes.DATASOURCE, field: ArtifactIndexFields.DATA_SOURCES },\n { type: ArtifactTypes.COMPONENT, field: ArtifactIndexFields.COMPONENTS },\n { type: ArtifactTypes.REPOSITORY, field: ArtifactIndexFields.REPOSITORIES },\n { type: ArtifactTypes.SERVICE, field: ArtifactIndexFields.SERVICES },\n { type: ArtifactTypes.CONTROLLER, field: ArtifactIndexFields.CONTROLLERS },\n ];\n}\n\n/** Why a decorated class was left out of the index - reported, never silent. */\nexport class ScanSkipReasons {\n static readonly ABSTRACT = 'abstract';\n static readonly NOT_EXPORTED = 'not-exported';\n static readonly IGNORED = 'ignored';\n\n static readonly SCHEME_SET = new Set<string>([this.ABSTRACT, this.NOT_EXPORTED, this.IGNORED]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\n/** One of the `ScanSkipReasons` values. */\nexport type TScanSkipReason = TConstValue<typeof ScanSkipReasons>;\n"]}
@@ -1,14 +1,21 @@
1
1
  import type { AnyType, TClass } from '@venizia/ignis-helpers';
2
2
  import type { TArtifactIndexField, TArtifactType, TScanSkipReason } from './constants.js';
3
+ /** A decorated class the scanner put in the index. */
3
4
  export interface IScannedArtifact {
4
5
  className: string;
5
6
  /** Absolute path of the declaring file. */
6
7
  filePath: string;
7
8
  type: TArtifactType;
8
9
  }
10
+ /** Options for one scan of a source tree. */
9
11
  export interface IScanOptions {
10
12
  root: string;
11
- /** Glob patterns relative to `root`; defaults to `ArtifactStereotypes.DEFAULT_IGNORE`. */
13
+ /**
14
+ * Glob patterns relative to `root`, ignored in addition to `ArtifactStereotypes.DEFAULT_IGNORE`,
15
+ * which always apply.
16
+ *
17
+ * @default []
18
+ */
12
19
  ignore?: string[];
13
20
  /** Module specifiers, matched exactly, whose stereotype imports also count - a package that re-exports the decorators. Adds to `ArtifactStereotypes.SOURCE_MODULES`. */
14
21
  sourceModules?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/generator/common/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnyType, TClass } from '@venizia/ignis-helpers';\nimport type { TArtifactIndexField, TArtifactType, TScanSkipReason } from './constants';\n\nexport interface IScannedArtifact {\n className: string;\n /** Absolute path of the declaring file. */\n filePath: string;\n type: TArtifactType;\n}\n\nexport interface IScanOptions {\n root: string;\n /** Glob patterns relative to `root`; defaults to `ArtifactStereotypes.DEFAULT_IGNORE`. */\n ignore?: string[];\n /** Module specifiers, matched exactly, whose stereotype imports also count - a package that re-exports the decorators. Adds to `ArtifactStereotypes.SOURCE_MODULES`. */\n sourceModules?: string[];\n /** Recognise a stereotype imported from any module whose exports lead, through `export *` and renaming re-exports, to a source module - a framework that re-exports the kernel's decorators. */\n followReexports?: boolean;\n}\n\n/** A decorated class the index leaves out, and why. */\nexport interface IScanSkipped {\n className: string;\n filePath: string;\n reason: TScanSkipReason;\n}\n\n/** The index content plus what a caller's `ignore` silently left out: decorated classes under a user pattern, never under a default one. */\nexport interface IScanReport {\n artifacts: IScannedArtifact[];\n ignored: IScannedArtifact[];\n /** Every decorated class left out - abstract, not a named export, or under a user ignore pattern. */\n skipped: IScanSkipped[];\n}\n\n/** The object a generated index exports - structurally the kernel's `IArtifactIndex` (boot does not depend on the kernel). */\nexport type TGeneratedArtifactIndex = Partial<\n Record<TArtifactIndexField, ReadonlyArray<TClass<AnyType>>>\n>;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/generator/common/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnyType, TClass } from '@venizia/ignis-helpers';\nimport type { TArtifactIndexField, TArtifactType, TScanSkipReason } from './constants';\n\n/** A decorated class the scanner put in the index. */\nexport interface IScannedArtifact {\n className: string;\n /** Absolute path of the declaring file. */\n filePath: string;\n type: TArtifactType;\n}\n\n/** Options for one scan of a source tree. */\nexport interface IScanOptions {\n root: string;\n /**\n * Glob patterns relative to `root`, ignored in addition to `ArtifactStereotypes.DEFAULT_IGNORE`,\n * which always apply.\n *\n * @default []\n */\n ignore?: string[];\n /** Module specifiers, matched exactly, whose stereotype imports also count - a package that re-exports the decorators. Adds to `ArtifactStereotypes.SOURCE_MODULES`. */\n sourceModules?: string[];\n /** Recognise a stereotype imported from any module whose exports lead, through `export *` and renaming re-exports, to a source module - a framework that re-exports the kernel's decorators. */\n followReexports?: boolean;\n}\n\n/** A decorated class the index leaves out, and why. */\nexport interface IScanSkipped {\n className: string;\n filePath: string;\n reason: TScanSkipReason;\n}\n\n/** The index content plus what a caller's `ignore` silently left out: decorated classes under a user pattern, never under a default one. */\nexport interface IScanReport {\n artifacts: IScannedArtifact[];\n ignored: IScannedArtifact[];\n /** Every decorated class left out - abstract, not a named export, or under a user ignore pattern. */\n skipped: IScanSkipped[];\n}\n\n/** The object a generated index exports - structurally the kernel's `IArtifactIndex` (boot does not depend on the kernel). */\nexport type TGeneratedArtifactIndex = Partial<\n Record<TArtifactIndexField, ReadonlyArray<TClass<AnyType>>>\n>;\n"]}
@@ -1,9 +1,14 @@
1
1
  import type { IScanReport, IScannedArtifact } from './common/index.js';
2
+ /** Options for writing or checking the artifact index file. */
2
3
  export interface IGenerateOptions {
3
4
  root: string;
4
5
  out: string;
5
6
  ignore?: string[];
6
- /** Name of the exported constant; default `GeneratedArtifacts`. */
7
+ /**
8
+ * Name of the exported constant.
9
+ *
10
+ * @default 'GeneratedArtifacts'
11
+ */
7
12
  exportName?: string;
8
13
  /** Extra module specifiers whose stereotype imports count; see `IScanOptions.sourceModules`. */
9
14
  sourceModules?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../src/generator/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { IScanReport, IScannedArtifact } from './common';\nimport { ArtifactIndexEmitter } from './emitter';\nimport { ArtifactScanner } from './scanner';\n\nexport interface IGenerateOptions {\n root: string;\n out: string;\n ignore?: string[];\n /** Name of the exported constant; default `GeneratedArtifacts`. */\n exportName?: string;\n /** Extra module specifiers whose stereotype imports count; see `IScanOptions.sourceModules`. */\n sourceModules?: string[];\n}\n\n/** Writes the artifact index, and checks that the committed one is still current. */\nexport class ArtifactIndexGenerator {\n private static render(opts: IGenerateOptions): { content: string } & IScanReport {\n const { artifacts, ignored, skipped } = ArtifactScanner.getInstance().scanWithReport({\n root: opts.root,\n ignore: opts.ignore,\n sourceModules: opts.sourceModules,\n });\n const content = ArtifactIndexEmitter.render({\n artifacts,\n outFile: resolve(opts.out),\n exportName: opts.exportName ?? ArtifactIndexEmitter.DEFAULT_EXPORT_NAME,\n command: {\n root: opts.root,\n out: opts.out,\n ignore: opts.ignore,\n sourceModules: opts.sourceModules,\n },\n });\n\n return { content, artifacts, ignored, skipped };\n }\n\n /** Everything below the first line: the header only records the command, so a flag change alone must not read as drift. */\n private static bodyOf(content: string): string {\n return content.slice(content.indexOf('\\n') + 1);\n }\n\n /** Writes the index only when its content changed, so an unchanged tree leaves the file's mtime alone. */\n static generate(opts: IGenerateOptions): { content: string; written: boolean } & IScanReport {\n const { content, artifacts, ignored, skipped } = ArtifactIndexGenerator.render(opts);\n const out = resolve(opts.out);\n const current = existsSync(out) ? readFileSync(out, 'utf8') : undefined;\n\n if (current === content) {\n return { content, artifacts, ignored, skipped, written: false };\n }\n\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, content);\n\n return { content, artifacts, ignored, skipped, written: true };\n }\n\n /** Renders in memory and compares the body with the committed file - the staleness gate for lint and CI. */\n static check(opts: IGenerateOptions): {\n isFresh: boolean;\n expected: string;\n actual: string | undefined;\n ignored: IScannedArtifact[];\n } {\n const { content: expected, ignored } = ArtifactIndexGenerator.render(opts);\n const out = resolve(opts.out);\n const actual = existsSync(out) ? readFileSync(out, 'utf8') : undefined;\n const isFresh =\n actual !== undefined &&\n ArtifactIndexGenerator.bodyOf(actual) === ArtifactIndexGenerator.bodyOf(expected);\n\n return { isFresh, expected, actual, ignored };\n }\n}\n"]}
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../src/generator/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { IScanReport, IScannedArtifact } from './common';\nimport { ArtifactIndexEmitter } from './emitter';\nimport { ArtifactScanner } from './scanner';\n\n/** Options for writing or checking the artifact index file. */\nexport interface IGenerateOptions {\n root: string;\n out: string;\n ignore?: string[];\n /**\n * Name of the exported constant.\n *\n * @default 'GeneratedArtifacts'\n */\n exportName?: string;\n /** Extra module specifiers whose stereotype imports count; see `IScanOptions.sourceModules`. */\n sourceModules?: string[];\n}\n\n/** Writes the artifact index, and checks that the committed one is still current. */\nexport class ArtifactIndexGenerator {\n private static render(opts: IGenerateOptions): { content: string } & IScanReport {\n const { artifacts, ignored, skipped } = ArtifactScanner.getInstance().scanWithReport({\n root: opts.root,\n ignore: opts.ignore,\n sourceModules: opts.sourceModules,\n });\n const content = ArtifactIndexEmitter.render({\n artifacts,\n outFile: resolve(opts.out),\n exportName: opts.exportName ?? ArtifactIndexEmitter.DEFAULT_EXPORT_NAME,\n command: {\n root: opts.root,\n out: opts.out,\n ignore: opts.ignore,\n sourceModules: opts.sourceModules,\n },\n });\n\n return { content, artifacts, ignored, skipped };\n }\n\n /** Everything below the first line: the header only records the command, so a flag change alone must not read as drift. */\n private static bodyOf(content: string): string {\n return content.slice(content.indexOf('\\n') + 1);\n }\n\n /** Writes the index only when its content changed, so an unchanged tree leaves the file's mtime alone. */\n static generate(opts: IGenerateOptions): { content: string; written: boolean } & IScanReport {\n const { content, artifacts, ignored, skipped } = ArtifactIndexGenerator.render(opts);\n const out = resolve(opts.out);\n const current = existsSync(out) ? readFileSync(out, 'utf8') : undefined;\n\n if (current === content) {\n return { content, artifacts, ignored, skipped, written: false };\n }\n\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, content);\n\n return { content, artifacts, ignored, skipped, written: true };\n }\n\n /** Renders in memory and compares the body with the committed file - the staleness gate for lint and CI. */\n static check(opts: IGenerateOptions): {\n isFresh: boolean;\n expected: string;\n actual: string | undefined;\n ignored: IScannedArtifact[];\n } {\n const { content: expected, ignored } = ArtifactIndexGenerator.render(opts);\n const out = resolve(opts.out);\n const actual = existsSync(out) ? readFileSync(out, 'utf8') : undefined;\n const isFresh =\n actual !== undefined &&\n ArtifactIndexGenerator.bodyOf(actual) === ArtifactIndexGenerator.bodyOf(expected);\n\n return { isFresh, expected, actual, ignored };\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/ignis-boot",
3
- "version": "0.4.8-0",
3
+ "version": "0.4.8-2",
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",
@@ -80,12 +80,12 @@
80
80
  "test": "bun test ./src"
81
81
  },
82
82
  "dependencies": {
83
- "@venizia/ignis-helpers": "0.4.8-0",
84
- "@venizia/ignis-inversion": "0.4.7-0"
83
+ "@venizia/ignis-helpers": "0.4.8-2",
84
+ "@venizia/ignis-inversion": "0.4.7-2"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@types/bun": "^1.4.3",
88
- "@venizia/dev-configs": "0.4.8-0",
88
+ "@venizia/dev-configs": "0.4.8-2",
89
89
  "eslint": "^10.13.0",
90
90
  "oxlint": "1.89.0",
91
91
  "oxlint-tsgolint": "7.0.2004",