archicat 0.0.5 → 0.0.7

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  The generative architecture framework for clean architecture.
6
6
 
7
- Archicat generates a module mirror from your source code. Public APIs become aliases. Implementations stay private. The mirror is the boundary.
7
+ Archicat generates a mirror from your source code. APIs become aliases. Implementations stay behind architecture rules.
8
8
 
9
9
  ```bash
10
10
  npm i -D archicat
@@ -12,53 +12,111 @@ npm i -D archicat
12
12
 
13
13
  ## Why
14
14
 
15
- Architecture should be enforceable.
15
+ TypeScript asks: can this import resolve?
16
16
 
17
- Your code stays yours.
17
+ Archicat asks: should this import exist?
18
18
 
19
- ##
19
+ ## Definitions
20
20
 
21
- **M²** means **Modular Mirroring**.
21
+ ### Module
22
22
 
23
- ```txt
24
- source modules
25
- -> module definitions
26
- -> generated mirror
27
- -> checked boundaries
28
- ```
29
-
30
- You define the module:
23
+ Business/application unit.
31
24
 
32
25
  ```ts
33
26
  import { defineModule } from 'archicat';
34
27
 
35
28
  export default defineModule({
36
- id: 'media',
29
+ name: 'media',
30
+
31
+ api: {
32
+ root: './api',
33
+ dependencies: ['module.account.api', 'library.error.api'],
34
+ },
35
+
36
+ impl: {
37
+ root: './impl',
38
+ dependencies: ['module.account.api', 'library.backend.api'],
39
+ },
40
+ });
41
+ ```
42
+
43
+ ### Library
44
+
45
+ Lower reusable unit.
46
+
47
+ ```ts
48
+ import { defineLibrary } from 'archicat';
49
+
50
+ export default defineLibrary({
51
+ name: 'backend',
52
+
37
53
  api: './api',
38
54
  impl: './impl',
39
- dependencies: ['module.account.api'],
40
55
  });
41
56
  ```
42
57
 
43
- Archicat mirrors it:
58
+ ### App
44
59
 
45
- ```txt
46
- .archicat/modules/media/
47
- api/
48
- impl/
60
+ Composition root.
61
+
62
+ ```ts
63
+ import { defineApp } from 'archicat';
64
+
65
+ export default defineApp({
66
+ name: 'main-api',
67
+ root: './src/app',
68
+
69
+ dependencies: [
70
+ 'module.media.impl',
71
+ 'library.backend.impl',
72
+ ],
73
+ });
49
74
  ```
50
75
 
51
- You import the mirror:
76
+ ## Dependency rules
77
+
78
+ ### Module
79
+
80
+ | Source | Can depend on | Cannot depend on |
81
+ |---|---|---|
82
+ | `module.*.api` | `module.*.api`, `library.*.api` | `module.*.impl`, `library.*.impl` |
83
+ | `module.*.impl` | own `module.*.api`, `module.*.api`, `library.*.api` | `module.*.impl`, `library.*.impl` |
84
+
85
+ ### Library
86
+
87
+ | Source | Can depend on | Cannot depend on |
88
+ |---|---|---|
89
+ | `library.*.api` | `library.*.api` | `module.*`, `library.*.impl` |
90
+ | `library.*.impl` | own `library.*.api`, `library.*.api` | `module.*`, `library.*.impl` |
91
+
92
+ ### App
93
+
94
+ | Source | Can depend on | Cannot depend on |
95
+ |---|---|---|
96
+ | `app.*` | `module.*.api`, `module.*.impl`, `library.*.api`, `library.*.impl` | nothing inside the Archicat graph |
97
+
98
+ > [!IMPORTANT]
99
+ > Implementation targets are wired by app composition. Normal modules and libraries depend on API targets.
100
+
101
+ ## Imports
102
+
103
+ Public API import:
52
104
 
53
105
  ```ts
54
106
  import { AccountReader } from '@module/account';
55
107
  ```
56
108
 
57
- Not the machinery:
109
+ App composition import:
58
110
 
59
111
  ```ts
60
- import { AccountRepository } from '@module/account/impl'; // does not exist
61
- import { AccountRepository } from '../../account/impl/repository'; // blocked
112
+ import { mediaAssembly } from '@module/media/impl';
113
+ ```
114
+
115
+ Blocked outside app composition:
116
+
117
+ ```ts
118
+ import { MediaRepository } from '@module/media/impl';
119
+ import { MediaRepository } from '../../media/impl/repository';
62
120
  ```
63
121
 
64
122
  ## Config
@@ -67,30 +125,59 @@ import { AccountRepository } from '../../account/impl/repository'; // blocked
67
125
  import { defineArchicatConfig } from 'archicat';
68
126
 
69
127
  export default defineArchicatConfig({
128
+ typescript: {
129
+ tsConfig: {
130
+ extends: '../../tsconfig.node.json',
131
+ include: ['bootstrap.ts', 'src/app', 'src/libraries', 'src/modules', 'types'],
132
+ exclude: ['node_modules', 'dist'],
133
+ },
134
+ },
135
+
136
+ alias: {
137
+ '@app': './src/app/index.ts',
138
+ '@app/*': './src/app/*',
139
+ },
140
+
70
141
  modules: {
71
142
  include: ['./src/modules'],
72
143
  },
144
+
145
+ libraries: {
146
+ include: ['./src/libraries'],
147
+ },
148
+
149
+ apps: {
150
+ include: ['./src/app'],
151
+ },
73
152
  });
74
153
  ```
75
154
 
155
+ App `tsconfig.json`:
156
+
157
+ ```json
158
+ {
159
+ "extends": "./.archicat/tsconfig.json",
160
+ "compilerOptions": {
161
+ "rootDir": ".",
162
+ "outDir": "./dist"
163
+ }
164
+ }
165
+ ```
166
+
167
+ > [!IMPORTANT]
168
+ > Generated `.archicat/tsconfig.json` extends `typescript.tsConfig.extends`, therefore put user aliases in `archicat.config.ts`, not in `compilerOptions.paths`.
169
+
76
170
  ## Output
77
171
 
78
172
  ```txt
79
173
  .archicat/
80
174
  tsconfig.json
81
175
  modules/
176
+ libraries/
82
177
  types/
83
-
84
- archicat-report/
85
- build.json
86
- ```
87
-
88
- Extend the generated config:
89
-
90
- ```json
91
- {
92
- "extends": "./.archicat/tsconfig.json"
93
- }
178
+ reports/
179
+ build.report.json
180
+ graph.report.json
94
181
  ```
95
182
 
96
183
  ## Commands
@@ -1,24 +1,33 @@
1
- import e from"node:path";import t from"node:fs";import{createJiti as n}from"jiti";import r from"typescript";const i=Object.freeze({root:`.`,outDir:`.archicat`,reportDir:`archicat-report`,prefixes:Object.freeze({module:`@module`,library:`@library`}),modules:Object.freeze({include:Object.freeze([`./src/modules`])}),libraries:Object.freeze({include:Object.freeze([])})});async function a(n=`archicat.config.ts`){let r=process.cwd(),i=e.resolve(r,n);if(!t.existsSync(i))throw Error(`Archicat config was not found: ${i}`);let a=await o(i,r);l(a,i);let u=s(a),d=e.resolve(r,u.root),f=e.resolve(d,u.outDir),p=e.resolve(d,u.reportDir),m=c(d,u.tsconfig);return{configFilePath:i,rootDir:d,outDir:f,reportDir:p,...m?{tsconfigPath:m}:{},config:a,resolvedConfig:u}}async function o(e,t){return await n(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function s(e){return{root:e.root??i.root,outDir:e.outDir??i.outDir,reportDir:e.reportDir??i.reportDir,...e.tsconfig===void 0?{}:{tsconfig:e.tsconfig},prefixes:{module:e.prefixes?.module??i.prefixes.module,library:e.prefixes?.library??i.prefixes.library},modules:{include:[...e.modules?.include??i.modules.include]},libraries:{include:[...e.libraries?.include??i.libraries.include]}}}function c(n,r){if(r){let i=e.resolve(n,r);if(!t.existsSync(i))throw Error(`Configured Archicat tsconfig was not found: ${i}`);return i}return[`tsconfig.base.json`,`tsconfig.json`].map(t=>e.join(n,t)).find(e=>t.existsSync(e))}function l(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat config: ${t}`);let n=e;u(n.root,`root`,t),u(n.outDir,`outDir`,t),u(n.reportDir,`reportDir`,t),u(n.tsconfig,`tsconfig`,t),d(n.modules?.include,`modules.include`,t),d(n.libraries?.include,`libraries.include`,t),f(n.prefixes?.module,`prefixes.module`,t),f(n.prefixes?.library,`prefixes.library`,t)}function u(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function d(e,t,n){if(e!==void 0&&(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``)))throw Error(`Archicat config ${t} must be an array of non-empty strings: ${n}`)}function f(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``||e.includes(`*`)||e.endsWith(`/`)))throw Error(`Archicat config ${t} must be a non-empty prefix without wildcard or trailing slash: ${n}`)}function p(e,t,n){let r=t.flatMap(t=>m(e,t,n));return Array.from(new Set(r)).sort((e,t)=>e.localeCompare(t))}function m(n,r,i){let a=e.resolve(n,r);if(r.includes(`*`))return ee(n,r).filter(t=>e.basename(t)===i);if(!t.existsSync(a))return[];let o=t.statSync(a);return o.isFile()?e.basename(a)===i?[a]:[]:o.isDirectory()?h(a,i):[]}function h(n,r){let i=[],a=t.readdirSync(n,{withFileTypes:!0});for(let t of a){if(ne(t.name))continue;let a=e.join(n,t.name);if(t.isDirectory()){i.push(...h(a,r));continue}t.isFile()&&t.name===r&&i.push(a)}return i}function ee(n,r){let i=e.resolve(n,r).split(e.sep);if(i.filter(e=>e.includes(`*`)).length!==1)throw Error(`Archicat supports exactly one wildcard segment per include pattern: ${r}`);let a=i.findIndex(e=>e.includes(`*`)),o=i.slice(0,a).join(e.sep)||e.sep,s=i[a]??`*`,c=i.slice(a+1),l=te(s);return t.existsSync(o)?t.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).filter(e=>l.test(e.name)).map(t=>e.join(o,t.name,...c)).filter(e=>t.existsSync(e)&&t.statSync(e).isFile()):[]}function te(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function ne(e){return[`node_modules`,`.git`,`.archicat`,`archicat-report`,`dist`,`build`,`coverage`].includes(e)}async function g(e,t){switch(t){case`module`:return re(e);case`library`:return ie(e)}}async function re(t){let n=await _(t,e.dirname(t));return v(n,t,`module`),{kind:`module`,contractFilePath:t,definitionDir:e.dirname(t),contract:n}}async function ie(t){let n=await _(t,e.dirname(t));return v(n,t,`library`),{kind:`library`,contractFilePath:t,definitionDir:e.dirname(t),contract:n}}async function _(e,t){return await n(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function v(e,t,n){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat ${n} definition: ${t}`);let r=e;if(r.kind!==n)throw Error(`Archicat ${n} file must export define${ae(n)}(...): ${t}`);if(typeof r.id!=`string`||r.id.trim()===``)throw Error(`Archicat ${n} must define a non-empty id: ${t}`);if(y(r.api,`api`,t),n===`module`&&y(r.impl,`impl`,t),!Array.isArray(r.dependencies))throw Error(`Archicat ${n} dependencies must be an array: ${t}`)}function y(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function ae(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function oe(e,t){let n=t.filter(e=>e.kind===`module`).map(t=>se(e,t)),r=t.filter(e=>e.kind===`library`).map(t=>ce(e,t)),i=[...n,...r];le(i);let a=x(i);return ue(i,a.targets),de(i),{rootDir:e.rootDir,outDir:e.outDir,reportDir:e.reportDir,...e.tsconfigPath?{tsconfigPath:e.tsconfigPath}:{},configFilePath:e.configFilePath,config:e.resolvedConfig,modules:n,libraries:r,definitions:i,graph:a}}function se(t,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;S(r.id,i,`module`);let o=r.api?b(a,r.api,`api`,r.id):void 0,s=r.impl?b(a,r.impl,`impl`,r.id):void 0,c=`${t.resolvedConfig.prefixes.module}/${r.id}`;return{kind:`module`,id:r.id,apiTarget:`module.${r.id}.api`,implTarget:`module.${r.id}.impl`,alias:c,aliasGlob:`${c}/*`,dependencies:[...r.dependencies],contractFilePath:i,definitionDir:a,apiRootPath:o,implRootPath:s,mirrorApiRootPath:e.join(t.outDir,`modules`,r.id,`api`),mirrorImplRootPath:e.join(t.outDir,`modules`,r.id,`impl`)}}function ce(t,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;S(r.id,i,`library`);let o=r.api?b(a,r.api,`api`,r.id):void 0,s=`${t.resolvedConfig.prefixes.library}/${r.id}`;return{kind:`library`,id:r.id,apiTarget:`library.${r.id}.api`,alias:s,aliasGlob:`${s}/*`,dependencies:[...r.dependencies],contractFilePath:i,definitionDir:a,apiRootPath:o,mirrorApiRootPath:e.join(t.outDir,`libraries`,r.id,`api`)}}function b(n,r,i,a){let o=e.resolve(n,r);if(!t.existsSync(o))throw Error(`Definition "${a}" declares ${i} root that does not exist: ${o}`);if(!t.statSync(o).isDirectory())throw Error(`Definition "${a}" declares ${i} root that is not a directory: ${o}`);return o}function x(e){let t=e.flatMap(e=>e.kind===`module`?[{key:e.apiTarget,kind:e.kind,id:e.id,surface:`api`},{key:e.implTarget,kind:e.kind,id:e.id,surface:`impl`}]:[{key:e.apiTarget,kind:e.kind,id:e.id,surface:`api`}]),n=e.flatMap(e=>{let t=e.kind===`module`?e.implTarget:e.apiTarget;return e.dependencies.map(e=>({from:t,to:e,origin:`declared`}))});return{targets:t,dependencies:[...e.filter(e=>e.kind===`module`).map(e=>({from:e.implTarget,to:e.apiTarget,origin:`derived`})),...n]}}function S(e,t,n){if(!/^[a-z][a-z0-9-]*$/u.test(e))throw Error(`Invalid Archicat ${n} id "${e}" in ${t}. Use ^[a-z][a-z0-9-]*$`)}function le(e){let t=new Map;for(let n of e){let e=`${n.kind}.${n.id}`,r=t.get(e);if(r)throw Error(`Duplicate Archicat ${n.kind} id "${n.id}" in ${r} and ${n.contractFilePath}`);t.set(e,n.contractFilePath)}}function ue(e,t){let n=new Set(t.map(e=>e.key));for(let r of e)for(let e of r.dependencies){if(!n.has(e))throw Error(`${C(r)} declares unknown dependency "${e}".`);let i=t.find(t=>t.key===e);if(i&&i.kind===r.kind&&i.id===r.id)throw Error(`${C(r)} cannot depend on itself: ${e}`)}}function de(e){let t=new Map(e.filter(e=>e.kind===`module`).map(e=>[e.apiTarget,e])),n=new Set,r=new Set,i=(e,a)=>{if(!r.has(e.id)){if(n.has(e.id))throw Error(`Cyclic Archicat module dependency detected: ${[...a,e.id].join(` -> `)}`);n.add(e.id);for(let n of e.dependencies){let r=t.get(n);r&&i(r,[...a,e.id])}n.delete(e.id),r.add(e.id)}};for(let e of t.values())i(e,[])}function C(e){return`${e.kind} "${e.id}"`}async function w(e){let t=await a(e),n=p(t.rootDir,t.resolvedConfig.modules.include,`archicat.module.ts`),r=p(t.rootDir,t.resolvedConfig.libraries.include,`archicat.library.ts`);if(n.length===0)throw Error(`No Archicat module definitions matched modules.include.`);return oe(t,[...await Promise.all(n.map(e=>g(e,`module`))),...await Promise.all(r.map(e=>g(e,`library`)))])}function T(t){return t.split(e.sep).join(`/`)}function fe(t,n){let r=e.dirname(t),i=e.parse(n),a=e.join(i.dir,i.name),o=T(e.relative(r,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function pe(t,n){let r=e.relative(n,t);return r===``||!!r&&!r.startsWith(`..`)&&!e.isAbsolute(r)}function E(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function D(t,n){return T(e.relative(t,n))}function O(e){return t.existsSync(e)?t.statSync(e).isFile()?k(e)?[e]:[]:A(e).filter(k).sort((e,t)=>e.localeCompare(t)):[]}function k(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function A(n){let r=[],i=t.readdirSync(n,{withFileTypes:!0});for(let t of i){let i=e.join(n,t.name);if(t.isDirectory()){r.push(...A(i));continue}t.isFile()&&r.push(i)}return r}function me(e){let n=r.createSourceFile(e,t.readFileSync(e,`utf8`),r.ScriptTarget.Latest,!0),i=[],a=e=>{if(r.isImportDeclaration(e)&&r.isStringLiteral(e.moduleSpecifier)&&i.push({moduleSpecifier:e.moduleSpecifier.text,kind:`import`}),r.isExportDeclaration(e)&&e.moduleSpecifier&&r.isStringLiteral(e.moduleSpecifier)&&i.push({moduleSpecifier:e.moduleSpecifier.text,kind:`export`}),r.isCallExpression(e)&&e.expression.kind===r.SyntaxKind.ImportKeyword){let[t]=e.arguments;t&&r.isStringLiteral(t)&&i.push({moduleSpecifier:t.text,kind:`dynamic-import`})}r.forEachChild(e,a)};return a(n),i}function j(e){let n=r.createSourceFile(e,t.readFileSync(e,`utf8`),r.ScriptTarget.Latest,!0),i=!1,a=e=>{if(!i){if(r.isExportAssignment(e)&&!e.isExportEquals){i=!0;return}if(M(e)){i=!0;return}if(r.isExportDeclaration(e)&&e.exportClause&&r.isNamedExports(e.exportClause))for(let t of e.exportClause.elements){let e=t.name.text,n=t.propertyName?.text;if(e==="default"||n==="default"){i=!0;return}}r.forEachChild(e,a)}};return a(n),i}function M(e){let t=r.canHaveModifiers(e)?r.getModifiers(e):void 0;if(!t)return!1;let n=t.some(e=>e.kind===r.SyntaxKind.ExportKeyword),i=t.some(e=>e.kind===r.SyntaxKind.DefaultKeyword);return n&&i}async function N(e){return P(await w(e))}function P(e){let t=[],n=e.definitions.flatMap(e=>F(e));for(let r of n){let n=z(e.definitions,r);if(n)for(let i of me(r)){let a=I(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function F(e){return e.kind===`module`?[...e.apiRootPath?O(e.apiRootPath):[],...e.implRootPath?O(e.implRootPath):[]]:e.apiRootPath?O(e.apiRootPath):[]}function I(e,t,n,r){let i=ge(e,r);if(i)return i.kind===t.kind&&i.id===t.id||t.dependencies.includes(i.target)?void 0:B(e,n,r,`${V(t.kind)} "${t.id}" imports "${i.target}" but does not declare it in dependencies.`);if(r.startsWith(`.`)||r.startsWith(`/`))return L(e,t,n,r)}function L(e,t,n,r){let i=R(n,r),a=z(e.definitions,i);if(!(!a||a.kind===t.kind&&a.id===t.id))return B(e,n,r,`${V(t.kind)} "${t.id}" imports ${a.kind} "${a.id}" through a source path. Use "${a.alias}" instead.`)}function R(t,n){return E(n.startsWith(`/`)?n:e.resolve(e.dirname(t),n))}function z(e,t){let n=E(t);return e.find(e=>he(e).filter(e=>!!e).some(e=>pe(n,E(e))))}function he(e){return e.kind===`module`?[e.apiRootPath,e.implRootPath,e.definitionDir]:[e.apiRootPath,e.definitionDir]}function ge(e,t){for(let n of e.definitions)if(t===n.alias||t.startsWith(`${n.alias}/`))return{kind:n.kind,id:n.id,target:n.apiTarget}}function B(e,t,n,r){return{filePath:D(e.rootDir,t),importPath:n,message:r}}function V(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function H(e){return{exitCode:0,lines:e.map(e=>({kind:`success`,message:e}))}}function _e(e){return{exitCode:1,lines:e.map(e=>({kind:`error`,message:e}))}}async function ve(e){let t=await N(e.config);return t.length===0?H([`Architecture check passed.`]):_e(t.map(e=>`${e.filePath}\n import: ${e.importPath}\n ${e.message}`))}async function ye(e){let t=await w(e);return[...be(t),...xe(t),...Se(t)]}function be(n){let r=e.join(n.outDir,`tsconfig.json`);return t.existsSync(r)?[]:[{severity:`warning`,message:`Generated tsconfig does not exist yet: ${r}. Run archicat generate.`}]}function xe(n){let r=e.join(n.rootDir,`tsconfig.json`);if(!t.existsSync(r))return[{severity:`warning`,message:`Root tsconfig.json was not found: ${r}`}];try{let e=JSON.parse(t.readFileSync(r,`utf8`)),n=[];return e.extends!==`./.archicat/tsconfig.json`&&e.extends!==`.archicat/tsconfig.json`&&n.push({severity:`warning`,message:`Root tsconfig.json should extend ./.archicat/tsconfig.json for Archicat aliases to work like Nuxt.`}),(e.compilerOptions?.rootDir===`src`||e.compilerOptions?.rootDir===`./src`)&&n.push({severity:`warning`,message:`compilerOptions.rootDir is set to src. Generated .archicat files live outside src and may break tsc.`}),n}catch(e){return[{severity:`warning`,message:`Failed to parse root tsconfig.json: ${e}`}]}}function Se(n){let r=[];for(let i of n.modules){let n=e.join(i.definitionDir,`api`),a=e.join(i.definitionDir,`impl`);!i.apiRootPath&&t.existsSync(n)&&r.push({severity:`warning`,message:`Module "${i.id}" has a physical api directory but its contract omits api. Archicat treats the public API as empty.`}),!i.implRootPath&&t.existsSync(a)&&r.push({severity:`warning`,message:`Module "${i.id}" has a physical impl directory but its contract omits impl. Archicat treats the implementation as no-op.`})}return r}async function Ce(e){let t=await ye(e.config);return t.length===0?H([`Doctor found no issues.`]):{exitCode:+!!t.some(e=>e.severity===`error`),lines:t.map(e=>({kind:e.severity===`error`?`error`:`warning`,message:e.message}))}}function U(e){t.existsSync(e)&&t.rmSync(e,{recursive:!0,force:!0}),t.mkdirSync(e,{recursive:!0})}function W(n,r){t.mkdirSync(e.dirname(n),{recursive:!0}),t.writeFileSync(n,r,`utf8`)}function G(e,t){W(e,`${JSON.stringify(t,null,2)}\n`)}function we(t){let n=`declare module 'archicat' {
2
- interface ArchicatProjectGraph {
3
- ${t.graph.targets.map(e=>` '${e.key}': true;`).join(`
4
- `)}
5
- }
1
+ import{createRequire as e}from"node:module";import t from"node:path";import n from"node:fs";import{createJiti as r}from"jiti";import i from"typescript";const a=Object.freeze({configFileName:`archicat.config.ts`,root:`.`,outDir:`.archicat`,alias:Object.freeze({}),generated:Object.freeze({reportsDirName:`reports`,buildReportFileName:`build.report.json`,graphReportFileName:`graph.report.json`,tsconfigFileName:`tsconfig.json`,typesInclude:`./types/**/*.d.ts`,ignoredDirectoryNames:Object.freeze([`node_modules`,`.git`,`.archicat`,`archicat-report`,`dist`,`build`,`coverage`])}),typescript:Object.freeze({consumerTsconfigFileName:`tsconfig.json`,tsConfig:Object.freeze({include:Object.freeze([]),exclude:Object.freeze([]),files:Object.freeze([])})}),prefixes:Object.freeze({module:`@module`,library:`@library`}),modules:Object.freeze({include:Object.freeze([`./src/modules`])}),libraries:Object.freeze({include:Object.freeze([])}),apps:Object.freeze({include:Object.freeze([])})});function o(e){let t=n.readFileSync(e,`utf8`),r=i.parseConfigFileTextToJson(e,t);if(r.error)throw Error(ee(r.error));if(r.config==null||typeof r.config!=`object`||Array.isArray(r.config))throw Error(`Invalid tsconfig object: ${e}`);return r.config}function s(e,t=`tsconfig`){let n=e.compilerOptions;if(n==null)return{};if(typeof n!=`object`||Array.isArray(n))throw Error(`Tsconfig compilerOptions must be an object: ${t}`);return n}function c(e,t){let n=e.extends;if(n===void 0)return[];if(typeof n==`string`)return[u(t,n)];if(Array.isArray(n)&&n.every(e=>typeof e==`string`))return n.map(e=>u(t,e));throw Error(`Tsconfig extends must be a string or string array: ${t}`)}function l(n,r){return t.isAbsolute(r)||r.startsWith(`.`)?f(t.resolve(n,r),r):d(e(t.join(n,a.configFileName)),r,r)}function u(n,r){return t.isAbsolute(r)||r.startsWith(`.`)?f(t.resolve(t.dirname(n),r),n):d(e(n),r,n)}function d(e,t,n){for(let n of p(t))try{return e.resolve(n)}catch{continue}throw Error(`Unable to resolve tsconfig extends "${t}": ${n}`)}function f(e,t){for(let t of p(e))if(n.existsSync(t)&&n.statSync(t).isFile())return t;throw Error(`Unable to resolve tsconfig extends "${e}": ${t}`)}function p(e){return[e,`${e}.json`,t.join(e,a.typescript.consumerTsconfigFileName)]}function ee(e){let t=i.flattenDiagnosticMessageText(e.messageText,`
2
+ `);if(e.file&&e.start!==void 0){let n=e.file.getLineAndCharacterOfPosition(e.start);return`${e.file.fileName}:${n.line+1}:${n.character+1} - ${t}`}return t}async function te(e=a.configFileName){let r=process.cwd(),i=t.resolve(r,e);if(!n.existsSync(i))throw Error(`Archicat config was not found: ${i}`);let o=await ne(i,r);oe(o,i);let s=re(o),c=t.resolve(r,s.root),l=t.resolve(c,s.outDir),u=t.resolve(l,a.generated.reportsDirName),d=ae(c,s.typescript.tsConfig.extends);return{configFilePath:i,rootDir:c,outDir:l,reportsDir:u,...d?{tsconfigPath:d}:{},config:o,resolvedConfig:s}}async function ne(e,t){return await r(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function re(e){return{root:e.root??a.root,outDir:e.outDir??a.outDir,typescript:ie(e),alias:{...a.alias,...e.alias??{}},prefixes:{module:e.prefixes?.module??a.prefixes.module,library:e.prefixes?.library??a.prefixes.library},modules:m(e.modules,a.modules),libraries:m(e.libraries,a.libraries),apps:m(e.apps,a.apps)}}function ie(e){let t=e.typescript?.tsConfig,n=a.typescript.tsConfig,r={include:[...t?.include??n.include],exclude:[...t?.exclude??n.exclude],files:[...t?.files??n.files]};return t?.extends&&(r.extends=t.extends),{tsConfig:r}}function m(e,t){return{include:[...e?.include??t.include]}}function ae(e,t){if(t)return l(e,t)}function oe(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat config: ${t}`);let n=e;h(n.root,`root`,t),h(n.outDir,`outDir`,t),se(n.typescript?.tsConfig,t),g(n.modules?.include,`modules.include`,t),g(n.libraries?.include,`libraries.include`,t),g(n.apps?.include,`apps.include`,t),le(n.alias,`alias`,t),_(n.prefixes?.module,`prefixes.module`,t),_(n.prefixes?.library,`prefixes.library`,t)}function se(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config typescript.tsConfig must be an object: ${t}`);let n=e;h(n.extends,`typescript.tsConfig.extends`,t),g(n.include,`typescript.tsConfig.include`,t),g(n.exclude,`typescript.tsConfig.exclude`,t),g(n.files,`typescript.tsConfig.files`,t),ce(n.compilerOptions,t)}function ce(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config typescript.tsConfig.compilerOptions must be an object: ${t}`);let n=e;if(Object.hasOwn(n,`paths`))throw Error(`Archicat config typescript.tsConfig.compilerOptions.paths is not supported. Move aliases into archicat.config.ts alias.`);if(Object.hasOwn(n,`baseUrl`))throw Error(`Archicat config typescript.tsConfig.compilerOptions.baseUrl is not supported. Move aliases into archicat.config.ts alias.`);if(Object.keys(n).length>0)throw Error(`Archicat config typescript.tsConfig.compilerOptions is not supported. Put compiler options in the base or app tsconfig.`)}function h(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function g(e,t,n){if(e!==void 0&&(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``)))throw Error(`Archicat config ${t} must be an array of non-empty strings: ${n}`)}function _(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``||e.includes(`*`)||e.endsWith(`/`)))throw Error(`Archicat config ${t} must be a non-empty prefix without wildcard or trailing slash: ${n}`)}function le(e,t,n){if(e!==void 0){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config ${t} must be an object of non-empty string aliases: ${n}`);for(let[r,i]of Object.entries(e))if(r.trim()===``||typeof i!=`string`||i.trim()===``)throw Error(`Archicat config ${t} must contain non-empty string aliases: ${n}`)}}function v(e,t,n){let r=t.flatMap(t=>ue(e,t,n));return Array.from(new Set(r)).sort((e,t)=>e.localeCompare(t))}function ue(e,r,i){let a=t.resolve(e,r);if(r.includes(`*`))return de(e,r).filter(e=>t.basename(e)===i);if(!n.existsSync(a))return[];let o=n.statSync(a);return o.isFile()?t.basename(a)===i?[a]:[]:o.isDirectory()?y(a,i):[]}function y(e,r){let i=[],a=n.readdirSync(e,{withFileTypes:!0});for(let n of a){if(pe(n.name))continue;let a=t.join(e,n.name);if(n.isDirectory()){i.push(...y(a,r));continue}n.isFile()&&n.name===r&&i.push(a)}return i}function de(e,r){let i=t.resolve(e,r).split(t.sep);if(i.filter(e=>e.includes(`*`)).length!==1)throw Error(`Archicat supports exactly one wildcard segment per include pattern: ${r}`);let a=i.findIndex(e=>e.includes(`*`)),o=i.slice(0,a).join(t.sep)||t.sep,s=i[a]??`*`,c=i.slice(a+1),l=fe(s);return n.existsSync(o)?n.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).filter(e=>l.test(e.name)).map(e=>t.join(o,e.name,...c)).filter(e=>n.existsSync(e)&&n.statSync(e).isFile()):[]}function fe(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function pe(e){return a.generated.ignoredDirectoryNames.includes(e)}async function b(e,t){switch(t){case`module`:return me(e);case`library`:return he(e);case`app`:return ge(e)}}async function me(e){let n=await x(e,t.dirname(e));return S(n,e,`module`),{kind:`module`,contractFilePath:e,definitionDir:t.dirname(e),contract:n}}async function he(e){let n=await x(e,t.dirname(e));return S(n,e,`library`),{kind:`library`,contractFilePath:e,definitionDir:t.dirname(e),contract:n}}async function ge(e){let n=await x(e,t.dirname(e));return S(n,e,`app`),{kind:`app`,contractFilePath:e,definitionDir:t.dirname(e),contract:n}}async function x(e,t){return await r(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function S(e,t,n){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat ${n} definition: ${t}`);let r=e;if(r.kind!==n)throw Error(`Archicat ${n} file must export define${ve(n)}(...): ${t}`);if(typeof r.name!=`string`||r.name.trim()===``)throw Error(`Archicat ${n} must define a non-empty name: ${t}`);if(n===`app`){_e(r.root,`root`,t),w(r.dependencies,t,n);return}let i=r;C(i.api,`api`,t,n),C(i.impl,`impl`,t,n)}function C(e,t,n,r){if(typeof e!=`object`||!e)throw Error(`Archicat ${r}.${t} must be a surface object: ${n}`);_e(e.root,`${t}.root`,n),w(e.dependencies,n,`${r}.${t}`)}function w(e,t,n){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${n} dependencies must be an array of non-empty strings: ${t}`)}function _e(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function ve(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function ye(e){let t=new Map;for(let n of e){let e=t.get(n.from)??[];e.push(n.to),t.set(n.from,e)}let n=new Set,r=new Set;for(let e of t.keys())T(e,t,n,r,[])}function T(e,t,n,r,i){if(!r.has(e)){if(n.has(e)){let t=i.indexOf(e),n=[...i.slice(t<0?0:t),e];throw Error(`Cyclic Archicat dependency detected: ${n.join(` -> `)}`)}n.add(e);for(let a of t.get(e)??[])T(a,t,n,r,[...i,e]);n.delete(e),r.add(e)}}function be(e){let t=/^(module|library)\.([a-z][a-z0-9-]*)\.(api|impl)$/u.exec(e);if(t)return{kind:t[1],name:t[2],surface:t[3]}}function xe(e){return`${e.kind}.${e.surface}`}function E(e,t,n){let r=be(t);if(!r)throw Error(`${D(e)} declares invalid dependency target "${t}".`);if(!n.has(t))throw Error(`${D(e)} declares unknown dependency "${t}".`);if(e.kind===r.kind&&e.name===r.name)throw Error(`${D(e)} cannot depend on itself: ${t}`);if(!Se(e,r))throw Error(`${D(e)} cannot depend on ${xe(r)} target "${t}".`)}function Se(e,t){switch(e.surface){case`api`:return e.kind===`module`?t.surface===`api`&&(t.kind===`module`||t.kind===`library`):e.kind===`library`?t.surface===`api`&&t.kind===`library`:!1;case`impl`:return e.kind===`module`?t.surface===`api`&&(t.kind===`module`||t.kind===`library`):e.kind===`library`?t.surface===`api`&&t.kind===`library`:!1;case`app`:return t.kind===`module`||t.kind===`library`}}function D(e){return e.kind===`app`?`App "${e.name}"`:`${Ce(e.kind)} "${e.name}" ${e.surface}`}function Ce(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function we(e,t){let n=t.filter(e=>e.kind===`module`).map(t=>Te(e,t)),r=t.filter(e=>e.kind===`library`).map(t=>Ee(e,t)),i=t.filter(e=>e.kind===`app`).map(e=>De(e)),a=[...n,...r];ke([...a,...i]);let o=Oe(a,i);return Ae(a,i,o.targets),ye(o.dependencies),{rootDir:e.rootDir,outDir:e.outDir,reportsDir:e.reportsDir,...e.tsconfigPath?{tsconfigPath:e.tsconfigPath}:{},configFilePath:e.configFilePath,config:e.resolvedConfig,modules:n,libraries:r,apps:i,definitions:a,graph:o}}function Te(e,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;A(r.name,i,`module`);let o=r.api.root?k(a,r.api.root,`api`,r.name):void 0,s=r.impl.root?k(a,r.impl.root,`impl`,r.name):void 0,c=`${e.resolvedConfig.prefixes.module}/${r.name}`;return{kind:`module`,name:r.name,apiTarget:`module.${r.name}.api`,implTarget:`module.${r.name}.impl`,alias:c,aliasGlob:`${c}/*`,implAlias:`${c}/impl`,implAliasGlob:`${c}/impl/*`,contractFilePath:i,definitionDir:a,api:O(o,r.api.dependencies,t.join(e.outDir,`modules`,r.name,`api`)),impl:O(s,r.impl.dependencies,t.join(e.outDir,`modules`,r.name,`impl`))}}function Ee(e,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;A(r.name,i,`library`);let o=r.api.root?k(a,r.api.root,`api`,r.name):void 0,s=r.impl.root?k(a,r.impl.root,`impl`,r.name):void 0,c=`${e.resolvedConfig.prefixes.library}/${r.name}`;return{kind:`library`,name:r.name,apiTarget:`library.${r.name}.api`,implTarget:`library.${r.name}.impl`,alias:c,aliasGlob:`${c}/*`,implAlias:`${c}/impl`,implAliasGlob:`${c}/impl/*`,contractFilePath:i,definitionDir:a,api:O(o,r.api.dependencies,t.join(e.outDir,`libraries`,r.name,`api`)),impl:O(s,r.impl.dependencies,t.join(e.outDir,`libraries`,r.name,`impl`))}}function De(e){let{contract:t,contractFilePath:n,definitionDir:r}=e;return A(t.name,n,`app`),{kind:`app`,name:t.name,target:`app.${t.name}`,contractFilePath:n,definitionDir:r,rootPath:t.root?k(r,t.root,`app`,t.name):r,dependencies:[...t.dependencies]}}function O(e,t,n){return{...e?{rootPath:e}:{},mirrorRootPath:n,dependencies:[...t]}}function k(e,r,i,a){let o=t.resolve(e,r);if(!n.existsSync(o))throw Error(`Definition "${a}" declares ${i} root that does not exist: ${o}`);if(!n.statSync(o).isDirectory())throw Error(`Definition "${a}" declares ${i} root that is not a directory: ${o}`);return o}function Oe(e,t){let n=e.flatMap(e=>[{key:e.apiTarget,kind:e.kind,name:e.name,surface:`api`},{key:e.implTarget,kind:e.kind,name:e.name,surface:`impl`}]),r=[...e.flatMap(e=>[...e.api.dependencies.map(t=>({from:e.apiTarget,to:t,origin:`declared`})),...e.impl.dependencies.map(t=>({from:e.implTarget,to:t,origin:`declared`}))]),...t.flatMap(e=>e.dependencies.map(t=>({from:e.target,to:t,origin:`declared`})))];return{targets:n,dependencies:[...e.map(e=>({from:e.implTarget,to:e.apiTarget,origin:`derived`})),...r]}}function A(e,t,n){if(!/^[a-z][a-z0-9-]*$/u.test(e))throw Error(`Invalid Archicat ${n} name "${e}" in ${t}. Use ^[a-z][a-z0-9-]*$`)}function ke(e){let t=new Map;for(let n of e){let e=`${n.kind}.${n.name}`,r=t.get(e);if(r)throw Error(`Duplicate Archicat ${n.kind} name "${n.name}" in ${r} and ${n.contractFilePath}`);t.set(e,n.contractFilePath)}}function Ae(e,t,n){let r=new Set(n.map(e=>e.key));for(let t of e){for(let e of t.api.dependencies)E(je(t,`api`),e,r);for(let e of t.impl.dependencies)E(je(t,`impl`),e,r)}for(let e of t)for(let t of e.dependencies)E({kind:`app`,name:e.name,surface:`app`,target:e.target},t,r)}function je(e,t){return{kind:e.kind,name:e.name,surface:t,target:t===`api`?e.apiTarget:e.implTarget}}async function j(e){let t=await te(e),n=v(t.rootDir,t.resolvedConfig.modules.include,`archicat.module.ts`),r=v(t.rootDir,t.resolvedConfig.libraries.include,`archicat.library.ts`),i=v(t.rootDir,t.resolvedConfig.apps.include,`archicat.app.ts`);if(n.length===0&&r.length===0&&i.length===0)throw Error(`No Archicat definition files matched configured include roots.`);return we(t,[...await Promise.all(n.map(e=>b(e,`module`))),...await Promise.all(r.map(e=>b(e,`library`))),...await Promise.all(i.map(e=>b(e,`app`)))])}function M(e){return e.split(t.sep).join(`/`)}function Me(e,n){let r=t.dirname(e),i=t.parse(n),a=t.join(i.dir,i.name),o=M(t.relative(r,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function N(e,n){let r=t.relative(n,e);return r===``||!!r&&!r.startsWith(`..`)&&!t.isAbsolute(r)}function P(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function F(e,n){return M(t.relative(e,n))}function I(e){return n.existsSync(e)?n.statSync(e).isFile()?Ne(e)?[e]:[]:Pe(e).filter(Ne).sort((e,t)=>e.localeCompare(t)):[]}function Ne(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function Pe(e){let r=[],i=n.readdirSync(e,{withFileTypes:!0});for(let n of i){let i=t.join(e,n.name);if(n.isDirectory()){r.push(...Pe(i));continue}n.isFile()&&r.push(i)}return r}function Fe(e){let t=i.createSourceFile(e,n.readFileSync(e,`utf8`),i.ScriptTarget.Latest,!0),r=[],a=e=>{if(i.isImportDeclaration(e)&&i.isStringLiteral(e.moduleSpecifier)&&r.push({moduleSpecifier:e.moduleSpecifier.text,kind:`import`}),i.isExportDeclaration(e)&&e.moduleSpecifier&&i.isStringLiteral(e.moduleSpecifier)&&r.push({moduleSpecifier:e.moduleSpecifier.text,kind:`export`}),i.isCallExpression(e)&&e.expression.kind===i.SyntaxKind.ImportKeyword){let[t]=e.arguments;t&&i.isStringLiteral(t)&&r.push({moduleSpecifier:t.text,kind:`dynamic-import`})}i.forEachChild(e,a)};return a(t),r}function Ie(e){let t=i.createSourceFile(e,n.readFileSync(e,`utf8`),i.ScriptTarget.Latest,!0),r=!1,a=e=>{if(!r){if(i.isExportAssignment(e)&&!e.isExportEquals){r=!0;return}if(Le(e)){r=!0;return}if(i.isExportDeclaration(e)&&e.exportClause&&i.isNamedExports(e.exportClause))for(let t of e.exportClause.elements){let e=t.name.text,n=t.propertyName?.text;if(e==="default"||n==="default"){r=!0;return}}i.forEachChild(e,a)}};return a(t),r}function Le(e){let t=i.canHaveModifiers(e)?i.getModifiers(e):void 0;if(!t)return!1;let n=t.some(e=>e.kind===i.SyntaxKind.ExportKeyword),r=t.some(e=>e.kind===i.SyntaxKind.DefaultKeyword);return n&&r}async function Re(e){return ze(await j(e))}function ze(e){let t=[],n=[...e.definitions.flatMap(e=>Be(e)),...e.apps.flatMap(e=>I(e.rootPath))];for(let r of n){let n=Ue(e,r);if(n)for(let i of Fe(r)){let a=Ve(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function Be(e){return[...e.api.rootPath?I(e.api.rootPath):[],...e.impl.rootPath?I(e.impl.rootPath):[]]}function Ve(e,t,n,r){let i=Ke(e,r);if(i)return qe(t,i)?void 0:i.surface===`impl`&&t.kind!==`app`?L(e,n,r,`${R(t)} cannot import implementation target "${i.target}". Implementation imports are allowed only from app composition roots.`):Je(e,t.target,i.target)?void 0:L(e,n,r,`${R(t)} imports "${i.target}" but does not declare a dependency that allows it.`);if(r.startsWith(`.`)||r.startsWith(`/`))return He(e,t,n,r)}function He(e,t,n,r){let i=Ue(e,We(n,r));if(!(!i||Ge(t,i)))return L(e,n,r,`${R(t)} imports ${R(i)} through a source path. Use an Archicat alias instead.`)}function Ue(e,t){let n=P(t);for(let t of e.definitions){if(t.api.rootPath&&N(n,P(t.api.rootPath)))return{kind:t.kind,name:t.name,surface:`api`,target:t.apiTarget,definition:t};if(t.impl.rootPath&&N(n,P(t.impl.rootPath)))return{kind:t.kind,name:t.name,surface:`impl`,target:t.implTarget,definition:t}}for(let t of e.apps)if(N(n,P(t.rootPath)))return{kind:`app`,name:t.name,surface:`app`,target:t.target,app:t}}function We(e,n){return P(n.startsWith(`/`)?n:t.resolve(t.dirname(e),n))}function Ge(e,t){return e.kind===t.kind&&e.name===t.name}function Ke(e,t){for(let n of e.definitions){if(n.implAlias&&(t===n.implAlias||t.startsWith(`${n.implAlias}/`)))return{kind:n.kind,name:n.name,surface:`impl`,target:n.implTarget};if(t===n.alias||t.startsWith(`${n.alias}/`))return{kind:n.kind,name:n.name,surface:`api`,target:n.apiTarget}}}function qe(e,t){return e.kind===t.kind&&e.name===t.name&&t.surface===`api`}function Je(e,t,n){let r=new Set,i=[t];for(;i.length>0;){let t=i.shift();if(t===n)return!0;if(!r.has(t)){r.add(t);for(let n of e.graph.dependencies.filter(e=>e.from===t))i.push(n.to)}}return!1}function L(e,t,n,r){return{filePath:F(e.rootDir,t),importPath:n,message:r}}function R(e){return e.kind===`app`?`App "${e.name}"`:`${Ye(e.kind)} "${e.name}" ${e.surface}`}function Ye(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function z(e){return{exitCode:0,lines:e.map(e=>({kind:`success`,message:e}))}}function Xe(e){return{exitCode:1,lines:e.map(e=>({kind:`error`,message:e}))}}async function Ze(e){let t=await Re(e.config);return t.length===0?z([`Architecture check passed.`]):Xe(t.map(e=>`${e.filePath}\n import: ${e.importPath}\n ${e.message}`))}async function Qe(e){let t=await j(e);return[...$e(t),...et(t),...ct(t)]}function $e(e){let t=B(e);return n.existsSync(t)?[]:[{severity:`warning`,message:`Generated tsconfig does not exist yet: ${t}. Run archicat generate.`}]}function et(e){let t=lt(e);if(!n.existsSync(t))return[{severity:`warning`,message:`Consumer tsconfig was not found: ${t}`}];let r=[],i=tt(t,r);if(!i)return r;let a=nt(i,t,r);return a?(rt(r,e,i),it(r,a),at(r,a),ot(r,a),st(r,i),r):r}function tt(e,t){try{return o(e)}catch(e){t.push({severity:`warning`,message:`Failed to parse consumer tsconfig: ${V(e)}`});return}}function nt(e,t,n){try{return s(e,t)}catch(e){n.push({severity:`warning`,message:V(e)});return}}function rt(e,t,n){let r=ut(t);n.extends!==r&&e.push({severity:`warning`,message:`Consumer tsconfig should extend ${r} for generated Archicat aliases to work.`})}function it(e,t){let n=t.rootDir;n!==`src`&&n!==`./src`||e.push({severity:`warning`,message:`compilerOptions.rootDir is set to src. Generated .archicat files live outside src and may break tsc.`})}function at(e,t){Object.hasOwn(t,`paths`)&&e.push({severity:`warning`,message:`compilerOptions.paths should move to archicat.config.ts alias. Consumer tsconfig paths can override generated Archicat aliases.`})}function ot(e,t){Object.hasOwn(t,`baseUrl`)&&e.push({severity:`warning`,message:`compilerOptions.baseUrl is not supported. Move aliases into archicat.config.ts alias.`})}function st(e,t){t.include===void 0&&t.exclude===void 0&&t.files===void 0||e.push({severity:`warning`,message:`Consumer tsconfig include/exclude/files should move to archicat.config.ts typescript.tsConfig so generated Archicat types stay included.`})}function ct(e){let r=[];for(let i of e.definitions){let e=t.join(i.definitionDir,`api`),a=t.join(i.definitionDir,`impl`);!i.api.rootPath&&n.existsSync(e)&&r.push({severity:`warning`,message:`${H(i.kind)} "${i.name}" has a physical api directory but its contract omits api.root. Archicat treats the public API as empty.`}),!i.impl.rootPath&&n.existsSync(a)&&r.push({severity:`warning`,message:`${H(i.kind)} "${i.name}" has a physical impl directory but its contract omits impl.root. Archicat treats the implementation as no-op.`})}return r}function lt(e){return t.join(e.rootDir,a.typescript.consumerTsconfigFileName)}function B(e){return t.join(e.outDir,a.generated.tsconfigFileName)}function ut(e){let n=M(t.relative(e.rootDir,B(e)));return dt(n)||(n=`./${n}`),n}function dt(e){return e.startsWith(`./`)||e.startsWith(`../`)}function V(e){return e instanceof Error?e.message:String(e)}function H(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}async function ft(e){let t=await Qe(e.config);return t.length===0?z([`Doctor found no issues.`]):{exitCode:+!!t.some(e=>e.severity===`error`),lines:t.map(e=>({kind:e.severity===`error`?`error`:`warning`,message:e.message}))}}function pt(e){n.existsSync(e)&&n.rmSync(e,{recursive:!0,force:!0}),n.mkdirSync(e,{recursive:!0})}function U(e,r){n.mkdirSync(t.dirname(e),{recursive:!0}),n.writeFileSync(e,r,`utf8`)}function W(e,t){U(e,`${JSON.stringify(t,null,2)}\n`)}function mt(e){let n=[...e.modules.map(e=>e.apiTarget),...e.libraries.map(e=>e.apiTarget)],r=n,i=e.libraries.map(e=>e.apiTarget),a=i,o=e.graph.targets.map(e=>e.key),s=`import 'archicat';
3
+
4
+ declare module 'archicat' {
5
+ ${G(`ArchicatModuleApiDependencies`,n)}
6
+
7
+ ${G(`ArchicatModuleImplDependencies`,r)}
8
+
9
+ ${G(`ArchicatLibraryApiDependencies`,i)}
10
+
11
+ ${G(`ArchicatLibraryImplDependencies`,a)}
12
+
13
+ ${G(`ArchicatAppDependencies`,o)}
6
14
  }
7
15
 
8
16
  export {};
9
- `;W(e.join(t.outDir,`types`,`graph.d.ts`),n)}function Te(e){for(let t of e)switch(t.kind){case`module`:Ee(t);break;case`library`:K(t);break}}function Ee(e){K(e),De(e)}function K(t){if(!t.apiRootPath){W(e.join(t.mirrorApiRootPath,`index.ts`),`${J()}export {};
10
- `);return}let n=O(t.apiRootPath),r=new Set;for(let i of n){let n=T(e.relative(t.apiRootPath,i));r.add(n),q(e.join(t.mirrorApiRootPath,n),i)}r.has(`index.ts`)||W(e.join(t.mirrorApiRootPath,`index.ts`),`${J()}export {};
11
- `)}function De(t){let n=t.implRootPath?Oe(t.implRootPath):void 0;if(!n){let n=`${J()}
12
- export const ArchicatModuleImplementation = {
13
- id: '${t.id}',
17
+ `;U(t.join(e.outDir,`types`,`graph.d.ts`),s)}function G(e,t){return` interface ${e} {\n${Array.from(new Set(t)).sort((e,t)=>e.localeCompare(t)).map(e=>` '${e}': true;`).join(`
18
+ `)}\n }`}function ht(e){for(let t of e)switch(t.kind){case`module`:gt(t);break;case`library`:_t(t);break}}function gt(e){K(e.api),q(e,`module`)}function _t(e){K(e.api),q(e,`library`)}function K(e){if(!e.rootPath){U(t.join(e.mirrorRootPath,`index.ts`),`${Y()}export {};
19
+ `);return}let n=I(e.rootPath),r=new Set;for(let i of n){let n=M(t.relative(e.rootPath,i));r.add(n),J(t.join(e.mirrorRootPath,n),i)}r.has(`index.ts`)||U(t.join(e.mirrorRootPath,`index.ts`),`${Y()}export {};
20
+ `)}function q(e,n){let r=e.impl.rootPath?vt(e.impl.rootPath):void 0;if(!r){let r=n===`module`?`ArchicatModuleImplementation`:`ArchicatLibraryImplementation`,i=`${Y()}
21
+ export const ${r} = {
22
+ name: '${e.name}',
14
23
  assemblies: [],
15
24
  schemas: [],
16
25
  routes: [],
17
26
  } as const;
18
27
 
19
- export default ArchicatModuleImplementation;
20
- `;W(e.join(t.mirrorImplRootPath,`index.ts`),n);return}q(e.join(t.mirrorImplRootPath,`index.ts`),n)}function q(e,t){let n=fe(e,t),r=j(t)?`export { default } from '${n}';\n`:``;W(e,`${J()}
28
+ export default ${r};
29
+ `;U(t.join(e.impl.mirrorRootPath,`index.ts`),i);return}J(t.join(e.impl.mirrorRootPath,`index.ts`),r)}function J(e,t){let n=Me(e,t),r=Ie(t)?`export { default } from '${n}';\n`:``;U(e,`${Y()}
21
30
  export * from '${n}';
22
- ${r}`)}function Oe(t){for(let n of[`index.ts`,`index.mts`,`index.cts`,`index.tsx`]){let r=e.join(t,n);if(O(r).length>0)return r}}function J(){return`// Mirrored by Archicat.
23
- `}function ke(t){G(e.join(t.reportDir,`build.json`),Ae(t))}function Ae(e){return{generatedBy:`archicat`,schemaVersion:1,prefixes:e.config.prefixes,targets:e.graph.targets.map(e=>e.key),definitions:e.definitions.map(t=>je(e,t)),dependencies:e.graph.dependencies}}function je(e,t){return t.kind===`module`?{kind:t.kind,id:t.id,targets:{api:t.apiTarget,impl:t.implTarget},aliases:{api:t.alias},dependencies:t.dependencies,contractFilePath:D(e.rootDir,t.contractFilePath),source:{root:D(e.rootDir,t.definitionDir),api:t.apiRootPath?D(e.rootDir,t.apiRootPath):void 0,impl:t.implRootPath?D(e.rootDir,t.implRootPath):void 0},mirror:{api:D(e.rootDir,t.mirrorApiRootPath),impl:D(e.rootDir,t.mirrorImplRootPath)}}:{kind:t.kind,id:t.id,targets:{api:t.apiTarget},aliases:{api:t.alias},dependencies:t.dependencies,contractFilePath:D(e.rootDir,t.contractFilePath),source:{root:D(e.rootDir,t.definitionDir),api:t.apiRootPath?D(e.rootDir,t.apiRootPath):void 0},mirror:{api:D(e.rootDir,t.mirrorApiRootPath)}}}function Me(t){let n=Fe(t.tsconfigPath?Pe(t.tsconfigPath):{}),r=Ie(n),i=Ne(t);Be(t,r,i);let a={compilerOptions:{...ze(t,He(n,[`baseUrl`,`paths`])),paths:{...Le(t,r),...i}},include:[`../src/**/*.ts`,`./**/*.ts`,`./types/**/*.d.ts`],exclude:[`../node_modules`,`../dist`]};G(e.join(t.outDir,`tsconfig.json`),a)}function Ne(t){let n={};for(let r of t.definitions)n[r.alias]=[Y(t.outDir,e.join(r.mirrorApiRootPath,`index.ts`))],n[r.aliasGlob]=[Y(t.outDir,e.join(r.mirrorApiRootPath,`*`))];return n}function Pe(e){let n=t.readFileSync(e,`utf8`);return JSON.parse(Ve(n))}function Fe(e){let t=e.compilerOptions;return t&&typeof t==`object`&&!Array.isArray(t)?t:{}}function Ie(e){let t=e.paths;if(!t||typeof t!=`object`||Array.isArray(t))return{};let n={};for(let[e,r]of Object.entries(t)){if(!Array.isArray(r)||!r.every(e=>typeof e==`string`))throw Error(`Tsconfig paths.${e} must be an array of strings.`);n[e]=[...r]}return n}function Le(t,n){if(!t.tsconfigPath)return n;let r=e.dirname(t.tsconfigPath),i={};for(let[e,a]of Object.entries(n))i[e]=a.map(e=>Re(t.outDir,r,e));return i}function Re(t,n,r){return e.isAbsolute(r)?Y(t,r):Y(t,e.resolve(n,r))}function ze(t,n){if(!t.tsconfigPath)return n;let r=e.dirname(t.tsconfigPath),i={...n};for(let n of[`rootDir`,`outDir`,`declarationDir`]){let a=i[n];if(typeof a==`string`){let o=e.isAbsolute(a)?a:e.resolve(r,a);i[n]=Y(t.outDir,o)}}return i}function Y(t,n){let r=T(e.relative(t,n));return r.startsWith(`.`)||(r=`./${r}`),r}function Be(e,t,n){let r=Object.keys(t),i=Object.keys(n),a=Object.values(e.config.prefixes);for(let e of r){if(i.includes(e))throw Error(`Tsconfig alias conflict: user tsconfig already defines "${e}", but Archicat needs it.`);for(let t of a)if(e===t||e===`${t}/*`||e.startsWith(`${t}/`))throw Error(`Tsconfig alias conflict: user tsconfig already defines "${e}" inside Archicat reserved prefix "${t}". Remove the alias or configure another Archicat prefix.`)}}function Ve(e){return e.replace(/\/\*[\s\S]*?\*\//gu,``).replace(/(^|[^:])\/\/.*$/gmu,`$1`)}function He(e,t){let n={...e};for(let e of t)delete n[e];return n}async function Ue(t){let n=await w(t);if(e.resolve(n.outDir)===e.resolve(n.rootDir))throw Error(`Archicat outDir cannot be the project root.`);if(e.resolve(n.reportDir)===e.resolve(n.rootDir))throw Error(`Archicat reportDir cannot be the project root.`);return U(n.outDir),U(n.reportDir),Te(n.definitions),we(n),Me(n),ke(n),n}async function We(e){let t=await Ue(e.config);return H([`Mirrored modules: ${t.modules.length}`,`Mirrored libraries: ${t.libraries.length}`])}function X(e){let t=[`Modules: ${e.modules.length}`,``];for(let n of e.modules)t.push(n.id),t.push(` api: ${n.apiTarget}`),t.push(` impl: ${n.implTarget}`),Z(t,e.graph.dependencies.filter(e=>e.from===n.implTarget)),t.push(``);t.push(`Libraries: ${e.libraries.length}`),e.libraries.length>0&&t.push(``);for(let n of e.libraries)t.push(n.id),t.push(` api: ${n.apiTarget}`),Z(t,e.graph.dependencies.filter(e=>e.from===n.apiTarget)),t.push(``);return Ge(t)}function Z(e,t){if(t.length===0){e.push(` dependsOn: none`);return}e.push(` dependsOn:`);for(let n of t){let t=n.origin===`derived`?` (derived)`:``;e.push(` ${n.to}${t}`)}}function Ge(e){let t=[...e];for(;t.at(-1)===``;)t.pop();return t}async function Ke(e){return{exitCode:0,lines:X(await w(e.config)).map(e=>({kind:`info`,message:e}))}}async function qe(e=process.argv.slice(2)){let[t,...n]=e;try{let e=await Je(t,Ye(n));if(!e)return;Xe(e),process.exitCode=e.exitCode}catch(e){$({kind:`error`,message:e instanceof Error?e.message:String(e)}),process.exitCode=1}}async function Je(e,t){switch(e){case`generate`:return We(t);case`check`:return ve(t);case`graph`:return Ke(t);case`doctor`:return Ce(t);case`help`:case`--help`:case`-h`:case void 0:Q();return;default:return $({kind:`error`,message:`Unknown command: ${e}`}),Q(),{exitCode:1,lines:[]}}}function Ye(e){let t={};for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`--config`||r===`-c`){let i=e[n+1];if(!i)throw Error(`${r} requires a value.`);t.config=i,n+=1}}return t}function Xe(e){for(let t of e.lines)$(t)}function Q(){console.log([`Archicat`,``,`Usage:`,` archicat generate [--config archicat.config.ts]`,` archicat check [--config archicat.config.ts]`,` archicat graph [--config archicat.config.ts]`,` archicat doctor [--config archicat.config.ts]`,``].join(`
24
- `))}function $(e){switch(e.kind){case`success`:console.log(`✓ ${e.message}`);return;case`warning`:console.warn(`! ${e.message}`);return;case`error`:console.error(`✗ ${e.message}`);return;case`info`:console.log(e.message);return}}export{qe as runMain};
31
+ ${r}`)}function vt(e){for(let n of[`index.ts`,`index.mts`,`index.cts`,`index.tsx`]){let r=t.join(e,n);if(I(r).length>0)return r}}function Y(){return`// Mirrored by Archicat.
32
+ `}function yt(e){W(t.join(e.reportsDir,a.generated.buildReportFileName),bt(e)),W(t.join(e.reportsDir,a.generated.graphReportFileName),xt(e))}function bt(e){return{generatedBy:`archicat`,schemaVersion:1,prefixes:e.config.prefixes,outputs:{outDir:F(e.rootDir,e.outDir),reportsDir:F(e.rootDir,e.reportsDir)},targets:e.graph.targets.map(e=>e.key),definitions:[...e.definitions.map(t=>St(e,t)),...e.apps.map(t=>({kind:t.kind,name:t.name,targets:{app:t.target},aliases:{},dependencies:t.dependencies,contractFilePath:F(e.rootDir,t.contractFilePath),source:{root:F(e.rootDir,t.rootPath)},mirror:{}}))],dependencies:e.graph.dependencies}}function xt(e){return{generatedBy:`archicat`,schemaVersion:1,targets:e.graph.targets.map(e=>e.key),dependencies:e.graph.dependencies}}function St(e,t){return{kind:t.kind,name:t.name,targets:{api:t.apiTarget,impl:t.implTarget},aliases:{api:t.alias,impl:e.apps.length>0?t.implAlias:void 0},dependencies:{api:t.api.dependencies,impl:t.impl.dependencies},contractFilePath:F(e.rootDir,t.contractFilePath),source:{root:F(e.rootDir,t.definitionDir),api:t.api.rootPath?F(e.rootDir,t.api.rootPath):void 0,impl:t.impl.rootPath?F(e.rootDir,t.impl.rootPath):void 0},mirror:{api:F(e.rootDir,t.api.mirrorRootPath),impl:F(e.rootDir,t.impl.mirrorRootPath)}}}function Ct(e){Nt(e.tsconfigPath),W(t.join(e.outDir,a.generated.tsconfigFileName),wt(e))}function wt(e){let t={compilerOptions:Tt(e),include:Dt(e)},n=Et(e),r=Ot(e),i=kt(e);return n&&(t.extends=n),r.length>0&&(t.exclude=r),i.length>0&&(t.files=i),t}function Tt(e){let t=jt(e),n=At(e);return Lt(e,t,n),{paths:{...t,...n}}}function Et(e){return e.tsconfigPath?Z(e.outDir,e.tsconfigPath):void 0}function Dt(e){return Mt([...X(e,e.config.typescript.tsConfig.include),a.generated.typesInclude])}function Ot(e){return X(e,e.config.typescript.tsConfig.exclude)}function kt(e){return X(e,e.config.typescript.tsConfig.files)}function At(e){let n={},r=e.apps.length>0;for(let i of e.definitions)n[i.alias]=[Z(e.outDir,t.join(i.api.mirrorRootPath,`index.ts`))],n[i.aliasGlob]=[Z(e.outDir,t.join(i.api.mirrorRootPath,`*`))],r&&i.implAlias&&i.implAliasGlob&&(n[i.implAlias]=[Z(e.outDir,t.join(i.impl.mirrorRootPath,`index.ts`))],n[i.implAliasGlob]=[Z(e.outDir,t.join(i.impl.mirrorRootPath,`*`))]);return n}function jt(e){let n={};for(let[r,i]of Object.entries(e.config.alias)){let a=t.isAbsolute(i)?i:t.resolve(e.rootDir,i);n[r]=[Z(e.outDir,a)]}return n}function X(e,n){return n.map(n=>{let r=t.isAbsolute(n)?n:t.resolve(e.rootDir,n);return Z(e.outDir,r)})}function Z(e,n){let r=M(t.relative(e,n));return r.startsWith(`.`)||(r=`./${r}`),r}function Mt(e){return[...new Set(e)]}function Nt(e){e&&Pt(e,new Set,new Set)}function Pt(e,n,r){let i=t.resolve(e);if(r.has(i))return;if(n.has(i))throw Error(`Circular tsconfig extends chain detected: ${i}`);n.add(i);let a=o(i),l=s(a,i);Ft(l,i),It(l,i);for(let e of c(a,i))Pt(e,n,r);n.delete(i),r.add(i)}function Ft(e,t){if(Object.hasOwn(e,`paths`))throw Error(`Base tsconfig compilerOptions.paths is not supported by Archicat. Move aliases into archicat.config.ts alias: ${t}`)}function It(e,t){if(Object.hasOwn(e,`baseUrl`))throw Error(`Base tsconfig compilerOptions.baseUrl is not supported by Archicat. Move aliases into archicat.config.ts alias: ${t}`)}function Lt(e,t,n){let r=Object.keys(t),i=Object.keys(n),a=Object.values(e.config.prefixes);for(let e of r){if(i.includes(e))throw Error(`Alias conflict: archicat.config.ts alias already defines "${e}", but Archicat needs it.`);for(let t of a)if(e===t||e===`${t}/*`||e.startsWith(`${t}/`))throw Error(`Alias conflict: archicat.config.ts alias "${e}" is inside Archicat reserved prefix "${t}". Remove the alias or configure another Archicat prefix.`)}}async function Rt(e){let r=await j(e);if(t.resolve(r.outDir)===t.resolve(r.rootDir))throw Error(`Archicat outDir cannot be the project root.`);return pt(r.outDir),n.mkdirSync(t.join(r.outDir,`modules`),{recursive:!0}),n.mkdirSync(t.join(r.outDir,`libraries`),{recursive:!0}),n.mkdirSync(t.join(r.outDir,`types`),{recursive:!0}),n.mkdirSync(r.reportsDir,{recursive:!0}),ht(r.definitions),mt(r),Ct(r),yt(r),r}async function zt(e){let t=await Rt(e.config);return z([`Mirrored modules: ${t.modules.length}`,`Mirrored libraries: ${t.libraries.length}`,`Resolved apps: ${t.apps.length}`])}function Bt(e){let t=[`Modules: ${e.modules.length}`,``];for(let n of e.modules)t.push(n.name),t.push(` api: ${n.apiTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.apiTarget),` api dependsOn`),t.push(` impl: ${n.implTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.implTarget),` impl dependsOn`),t.push(``);t.push(`Libraries: ${e.libraries.length}`),e.libraries.length>0&&t.push(``);for(let n of e.libraries)t.push(n.name),t.push(` api: ${n.apiTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.apiTarget),` api dependsOn`),t.push(` impl: ${n.implTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.implTarget),` impl dependsOn`),t.push(``);t.push(`Apps: ${e.apps.length}`),e.apps.length>0&&t.push(``);for(let n of e.apps)t.push(n.name),t.push(` app: ${n.target}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.target),` dependsOn`),t.push(``);return Vt(t)}function Q(e,t,n){if(t.length===0){e.push(`${n}: none`);return}e.push(`${n}:`);for(let n of t){let t=n.origin===`derived`?` (derived)`:``;e.push(` ${n.to}${t}`)}}function Vt(e){let t=[...e];for(;t.at(-1)===``;)t.pop();return t}async function Ht(e){return{exitCode:0,lines:Bt(await j(e.config)).map(e=>({kind:`info`,message:e}))}}async function Ut(e=process.argv.slice(2)){let[t,...n]=e;try{let e=await Wt(t,Gt(n));if(!e)return;Kt(e),process.exitCode=e.exitCode}catch(e){$({kind:`error`,message:e instanceof Error?e.message:String(e)}),process.exitCode=1}}async function Wt(e,t){switch(e){case`generate`:return zt(t);case`check`:return Ze(t);case`graph`:return Ht(t);case`doctor`:return ft(t);case`help`:case`--help`:case`-h`:case void 0:qt();return;default:return $({kind:`error`,message:`Unknown command: ${e}`}),qt(),{exitCode:1,lines:[]}}}function Gt(e){let t={};for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`--config`||r===`-c`){let i=e[n+1];if(!i)throw Error(`${r} requires a value.`);t.config=i,n+=1}}return t}function Kt(e){for(let t of e.lines)$(t)}function qt(){console.log([`Archicat`,``,`Usage:`,` archicat generate [--config archicat.config.ts]`,` archicat check [--config archicat.config.ts]`,` archicat graph [--config archicat.config.ts]`,` archicat doctor [--config archicat.config.ts]`,``].join(`
33
+ `))}function $(e){switch(e.kind){case`success`:console.log(`✓ ${e.message}`);return;case`warning`:console.warn(`! ${e.message}`);return;case`error`:console.error(`✗ ${e.message}`);return;case`info`:console.log(e.message);return}}export{Ut as runMain};
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e={}){return Object.freeze({...e.root===void 0?{}:{root:e.root},...e.outDir===void 0?{}:{outDir:e.outDir},...e.reportDir===void 0?{}:{reportDir:e.reportDir},...e.tsconfig===void 0?{}:{tsconfig:e.tsconfig},...e.prefixes===void 0?{}:{prefixes:Object.freeze({...e.prefixes.module===void 0?{}:{module:e.prefixes.module},...e.prefixes.library===void 0?{}:{library:e.prefixes.library}})},...e.modules===void 0?{}:{modules:Object.freeze({...e.modules.include===void 0?{}:{include:Object.freeze([...e.modules.include])}})},...e.libraries===void 0?{}:{libraries:Object.freeze({...e.libraries.include===void 0?{}:{include:Object.freeze([...e.libraries.include])}})}})}function t(e){return Object.freeze({kind:`library`,id:e.id,...e.api===void 0?{}:{api:e.api},dependencies:Object.freeze([...e.dependencies??[]])})}function n(e){return Object.freeze({kind:`module`,id:e.id,...e.api===void 0?{}:{api:e.api},...e.impl===void 0?{}:{impl:e.impl},dependencies:Object.freeze([...e.dependencies??[]])})}exports.defineArchicatConfig=e,exports.defineLibrary=t,exports.defineModule=n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){return Object.freeze({kind:`app`,name:e.name,...e.root===void 0?{}:{root:e.root},dependencies:Object.freeze([...e.dependencies??[]])})}function t(e){let t={...e};for(let e of Object.keys(t))t[e]===void 0&&delete t[e];return Object.freeze(t)}function n(e={}){return t({root:e.root,outDir:e.outDir,typescript:e.typescript?r(e.typescript):void 0,alias:e.alias?Object.freeze({...e.alias}):void 0,prefixes:e.prefixes?a(e.prefixes):void 0,modules:e.modules?o(e.modules):void 0,libraries:e.libraries?o(e.libraries):void 0,apps:e.apps?o(e.apps):void 0})}function r(e){return t({tsConfig:e.tsConfig?i(e.tsConfig):void 0})}function i(e){return t({extends:e.extends,include:e.include?Object.freeze([...e.include]):void 0,exclude:e.exclude?Object.freeze([...e.exclude]):void 0,files:e.files?Object.freeze([...e.files]):void 0,compilerOptions:e.compilerOptions?Object.freeze({...e.compilerOptions}):void 0})}function a(e){return t({module:e.module,library:e.library})}function o(e){return t({include:e.include?Object.freeze([...e.include]):void 0})}function s(e){return typeof e==`string`?Object.freeze({root:e,dependencies:Object.freeze([])}):t({root:e?.root,dependencies:Object.freeze([...e?.dependencies??[]])})}function c(e){return Object.freeze({kind:`library`,name:e.name,api:s(e.api),impl:s(e.impl)})}function l(e){return Object.freeze({kind:`module`,name:e.name,api:s(e.api),impl:s(e.impl)})}exports.defineApp=e,exports.defineArchicatConfig=n,exports.defineLibrary=c,exports.defineModule=l;
@@ -1,3 +1,79 @@
1
+ //#region src/configs/archicat-project-graph.d.ts
2
+ /**
3
+ * @description Generated dependency targets allowed in module API surfaces.
4
+ */
5
+ interface ArchicatModuleApiDependencies {}
6
+ /**
7
+ * @description Generated dependency targets allowed in module implementation surfaces.
8
+ */
9
+ interface ArchicatModuleImplDependencies {}
10
+ /**
11
+ * @description Generated dependency targets allowed in library API surfaces.
12
+ */
13
+ interface ArchicatLibraryApiDependencies {}
14
+ /**
15
+ * @description Generated dependency targets allowed in library implementation surfaces.
16
+ */
17
+ interface ArchicatLibraryImplDependencies {}
18
+ /**
19
+ * @description Generated dependency targets allowed in app composition roots.
20
+ */
21
+ interface ArchicatAppDependencies {}
22
+ /**
23
+ * @description Dependency key fallback used before `.archicat/types/graph.d.ts` exists.
24
+ */
25
+ type ArchicatDependencyKey<Dependencies> = keyof Dependencies extends never ? string : Extract<keyof Dependencies, string>;
26
+ /**
27
+ * @description Dependency target allowed from a module API surface.
28
+ */
29
+ type ArchicatModuleApiDependency = ArchicatDependencyKey<ArchicatModuleApiDependencies>;
30
+ /**
31
+ * @description Dependency target allowed from a module implementation surface.
32
+ */
33
+ type ArchicatModuleImplDependency = ArchicatDependencyKey<ArchicatModuleImplDependencies>;
34
+ /**
35
+ * @description Dependency target allowed from a library API surface.
36
+ */
37
+ type ArchicatLibraryApiDependency = ArchicatDependencyKey<ArchicatLibraryApiDependencies>;
38
+ /**
39
+ * @description Dependency target allowed from a library implementation surface.
40
+ */
41
+ type ArchicatLibraryImplDependency = ArchicatDependencyKey<ArchicatLibraryImplDependencies>;
42
+ /**
43
+ * @description Dependency target allowed from an app composition root.
44
+ */
45
+ type ArchicatAppDependency = ArchicatDependencyKey<ArchicatAppDependencies>;
46
+ //#endregion
47
+ //#region src/configs/app-config.d.ts
48
+ /**
49
+ * @description User-facing app composition definition input.
50
+ */
51
+ interface ArchicatAppInput {
52
+ /**
53
+ * @description Stable app name used in the Archicat project graph.
54
+ */
55
+ readonly name: string;
56
+ /**
57
+ * @description App source root, relative to the app definition file.
58
+ * @default The directory containing `archicat.app.ts`.
59
+ */
60
+ readonly root?: string;
61
+ /**
62
+ * @description Dependency targets visible from this app composition root.
63
+ * @default []
64
+ */
65
+ readonly dependencies?: readonly ArchicatAppDependency[];
66
+ }
67
+ /**
68
+ * @description Immutable app composition contract loaded by Archicat.
69
+ */
70
+ type ArchicatAppContract = Readonly<{
71
+ readonly kind: 'app';
72
+ readonly name: string;
73
+ readonly root?: string;
74
+ readonly dependencies: readonly ArchicatAppDependency[];
75
+ }>;
76
+ //#endregion
1
77
  //#region src/configs/archicat-config.d.ts
2
78
  /**
3
79
  * @description Definition discovery roots for one Archicat definition kind.
@@ -8,6 +84,49 @@ interface ArchicatDefinitionRootConfig {
8
84
  */
9
85
  readonly include?: readonly string[];
10
86
  }
87
+ /**
88
+ * @description TypeScript config fragment merged into generated `.archicat/tsconfig.json`.
89
+ */
90
+ interface ArchicatTypeScriptTsConfigInput {
91
+ /**
92
+ * @description Base TypeScript config extended by generated `.archicat/tsconfig.json`.
93
+ */
94
+ readonly extends?: string;
95
+ /**
96
+ * @description Project source files merged into generated `.archicat/tsconfig.json` include.
97
+ * Archicat rewrites relative paths to the generated config directory and appends generated type declarations automatically.
98
+ */
99
+ readonly include?: readonly string[];
100
+ /**
101
+ * @description Project paths merged into generated `.archicat/tsconfig.json` exclude.
102
+ * Archicat rewrites relative paths to the generated config directory.
103
+ */
104
+ readonly exclude?: readonly string[];
105
+ /**
106
+ * @description Project files merged into generated `.archicat/tsconfig.json` files.
107
+ * Archicat rewrites relative paths to the generated config directory.
108
+ */
109
+ readonly files?: readonly string[];
110
+ /**
111
+ * @description Unsupported. Put compiler options in the base or app tsconfig. Archicat owns generated `compilerOptions.paths` and does not support `baseUrl`.
112
+ */
113
+ readonly compilerOptions?: {
114
+ readonly paths?: never;
115
+ readonly baseUrl?: never;
116
+ };
117
+ }
118
+ /**
119
+ * @description TypeScript integration options used to generate `.archicat/tsconfig.json`.
120
+ */
121
+ interface ArchicatTypeScriptConfigInput {
122
+ /**
123
+ * @description Partial TypeScript config merged into generated `.archicat/tsconfig.json`.
124
+ * Archicat rewrites relative paths from the project root to `.archicat`, appends generated type declarations to `include`, and injects generated aliases into `compilerOptions.paths`.
125
+ * `compilerOptions` is not supported here. Put compiler policy in the base tsconfig and app build overrides in the app tsconfig.
126
+ * @default {}
127
+ */
128
+ readonly tsConfig?: ArchicatTypeScriptTsConfigInput;
129
+ }
11
130
  /**
12
131
  * @description TypeScript alias prefixes reserved by Archicat.
13
132
  */
@@ -23,6 +142,12 @@ interface ArchicatPrefixConfig {
23
142
  */
24
143
  readonly library?: string;
25
144
  }
145
+ /**
146
+ * @description User import aliases generated into `.archicat/tsconfig.json` together with Archicat module and library aliases.
147
+ * Aliases are resolved relative to the Archicat project root. Do not define TypeScript `compilerOptions.paths` manually for an Archicat project.
148
+ * @default {}
149
+ */
150
+ type ArchicatAliasConfig = Readonly<Record<string, string>>;
26
151
  /**
27
152
  * @description User-facing Archicat root config input.
28
153
  */
@@ -33,20 +158,20 @@ interface ArchicatConfigInput {
33
158
  */
34
159
  readonly root?: string;
35
160
  /**
36
- * @description Directory for generated mirror files and generated types.
161
+ * @description Directory for generated mirror files, generated types, and reports.
37
162
  * @default '.archicat'
38
163
  */
39
164
  readonly outDir?: string;
40
165
  /**
41
- * @description Directory for generated debug reports.
42
- * @default 'archicat-report'
166
+ * @description TypeScript integration options used to generate `.archicat/tsconfig.json`.
167
+ * @default {}
43
168
  */
44
- readonly reportDir?: string;
169
+ readonly typescript?: ArchicatTypeScriptConfigInput;
45
170
  /**
46
- * @description User tsconfig file to merge into the generated Archicat tsconfig.
47
- * @default Auto-detects tsconfig.base.json, then tsconfig.json.
171
+ * @description User TypeScript aliases generated by Archicat.
172
+ * @default {}
48
173
  */
49
- readonly tsconfig?: string;
174
+ readonly alias?: ArchicatAliasConfig;
50
175
  /**
51
176
  * @description Reserved TypeScript import prefixes generated by Archicat.
52
177
  * @default { module: '@module', library: '@library' }
@@ -62,6 +187,11 @@ interface ArchicatConfigInput {
62
187
  * @default { include: [] }
63
188
  */
64
189
  readonly libraries?: ArchicatDefinitionRootConfig;
190
+ /**
191
+ * @description App composition definition discovery config.
192
+ * @default { include: [] }
193
+ */
194
+ readonly apps?: ArchicatDefinitionRootConfig;
65
195
  }
66
196
  /**
67
197
  * @description Normalized immutable Archicat config contract.
@@ -69,8 +199,19 @@ interface ArchicatConfigInput {
69
199
  type ArchicatConfig = Readonly<{
70
200
  readonly root?: string;
71
201
  readonly outDir?: string;
72
- readonly reportDir?: string;
73
- readonly tsconfig?: string;
202
+ readonly typescript?: Readonly<{
203
+ readonly tsConfig?: Readonly<{
204
+ readonly extends?: string;
205
+ readonly include?: readonly string[];
206
+ readonly exclude?: readonly string[];
207
+ readonly files?: readonly string[];
208
+ readonly compilerOptions?: Readonly<{
209
+ readonly paths?: never;
210
+ readonly baseUrl?: never;
211
+ }>;
212
+ }>;
213
+ }>;
214
+ readonly alias?: ArchicatAliasConfig;
74
215
  readonly prefixes?: Readonly<{
75
216
  readonly module?: string;
76
217
  readonly library?: string;
@@ -81,17 +222,38 @@ type ArchicatConfig = Readonly<{
81
222
  readonly libraries?: Readonly<{
82
223
  readonly include?: readonly string[];
83
224
  }>;
225
+ readonly apps?: Readonly<{
226
+ readonly include?: readonly string[];
227
+ }>;
84
228
  }>;
85
229
  //#endregion
86
- //#region src/configs/archicat-project-graph.d.ts
230
+ //#region src/configs/surface-config.d.ts
231
+ /**
232
+ * @description Surface root shorthand or full surface config.
233
+ */
234
+ type ArchicatSurfaceInput<Dependency extends string> = string | ArchicatSurfaceConfig<Dependency>;
87
235
  /**
88
- * @description Generated Archicat project graph declaration surface.
236
+ * @description Source surface config.
89
237
  */
90
- interface ArchicatProjectGraph {}
238
+ interface ArchicatSurfaceConfig<Dependency extends string> {
239
+ /**
240
+ * @description Surface source root, relative to the definition file.
241
+ * @default Generates an empty mirror for the surface.
242
+ */
243
+ readonly root?: string;
244
+ /**
245
+ * @description Dependency targets visible from this surface.
246
+ * @default []
247
+ */
248
+ readonly dependencies?: readonly Dependency[];
249
+ }
91
250
  /**
92
- * @description Dependency reference from the generated Archicat project graph.
251
+ * @description Immutable normalized surface contract.
93
252
  */
94
- type ArchicatDependency = keyof ArchicatProjectGraph extends never ? string : keyof ArchicatProjectGraph;
253
+ type ArchicatSurfaceContract<Dependency extends string> = Readonly<{
254
+ readonly root?: string;
255
+ readonly dependencies: readonly Dependency[];
256
+ }>;
95
257
  //#endregion
96
258
  //#region src/configs/library-config.d.ts
97
259
  /**
@@ -99,28 +261,28 @@ type ArchicatDependency = keyof ArchicatProjectGraph extends never ? string : ke
99
261
  */
100
262
  interface ArchicatLibraryInput {
101
263
  /**
102
- * @description Stable library id used in the Archicat project graph.
264
+ * @description Stable library name used in the Archicat project graph.
103
265
  */
104
- readonly id: string;
266
+ readonly name: string;
105
267
  /**
106
- * @description Library public API root, relative to the library definition file.
268
+ * @description Library public API surface.
107
269
  * @default Generates an empty public API mirror.
108
270
  */
109
- readonly api?: string;
271
+ readonly api?: ArchicatSurfaceInput<ArchicatLibraryApiDependency>;
110
272
  /**
111
- * @description Public graph dependencies this library may import.
112
- * @default []
273
+ * @description Library implementation surface.
274
+ * @default Generates a no-op implementation mirror.
113
275
  */
114
- readonly dependencies?: readonly ArchicatDependency[];
276
+ readonly impl?: ArchicatSurfaceInput<ArchicatLibraryImplDependency>;
115
277
  }
116
278
  /**
117
279
  * @description Immutable library definition contract loaded by Archicat.
118
280
  */
119
281
  type ArchicatLibraryContract = Readonly<{
120
282
  readonly kind: 'library';
121
- readonly id: string;
122
- readonly api?: string;
123
- readonly dependencies: readonly ArchicatDependency[];
283
+ readonly name: string;
284
+ readonly api: ArchicatSurfaceContract<ArchicatLibraryApiDependency>;
285
+ readonly impl: ArchicatSurfaceContract<ArchicatLibraryImplDependency>;
124
286
  }>;
125
287
  //#endregion
126
288
  //#region src/configs/module-config.d.ts
@@ -129,36 +291,36 @@ type ArchicatLibraryContract = Readonly<{
129
291
  */
130
292
  interface ArchicatModuleInput {
131
293
  /**
132
- * @description Stable module id used in the Archicat project graph.
294
+ * @description Stable module name used in the Archicat project graph.
133
295
  */
134
- readonly id: string;
296
+ readonly name: string;
135
297
  /**
136
- * @description Module public API root, relative to the module definition file.
298
+ * @description Module public API surface.
137
299
  * @default Generates an empty public API mirror.
138
300
  */
139
- readonly api?: string;
301
+ readonly api?: ArchicatSurfaceInput<ArchicatModuleApiDependency>;
140
302
  /**
141
- * @description Module implementation root, relative to the module definition file.
303
+ * @description Module implementation surface.
142
304
  * @default Generates a no-op implementation mirror.
143
305
  */
144
- readonly impl?: string;
145
- /**
146
- * @description Public graph dependencies this module may import.
147
- * @default []
148
- */
149
- readonly dependencies?: readonly ArchicatDependency[];
306
+ readonly impl?: ArchicatSurfaceInput<ArchicatModuleImplDependency>;
150
307
  }
151
308
  /**
152
309
  * @description Immutable module definition contract loaded by Archicat.
153
310
  */
154
311
  type ArchicatModuleContract = Readonly<{
155
312
  readonly kind: 'module';
156
- readonly id: string;
157
- readonly api?: string;
158
- readonly impl?: string;
159
- readonly dependencies: readonly ArchicatDependency[];
313
+ readonly name: string;
314
+ readonly api: ArchicatSurfaceContract<ArchicatModuleApiDependency>;
315
+ readonly impl: ArchicatSurfaceContract<ArchicatModuleImplDependency>;
160
316
  }>;
161
317
  //#endregion
318
+ //#region src/configs/define-app-config.d.ts
319
+ /**
320
+ * @description Defines one Archicat app composition root.
321
+ */
322
+ declare function defineApp(app: ArchicatAppInput): ArchicatAppContract;
323
+ //#endregion
162
324
  //#region src/configs/define-archicat-config.d.ts
163
325
  /**
164
326
  * @description Defines the root Archicat config.
@@ -177,4 +339,4 @@ declare function defineLibrary(library: ArchicatLibraryInput): ArchicatLibraryCo
177
339
  */
178
340
  declare function defineModule(module: ArchicatModuleInput): ArchicatModuleContract;
179
341
  //#endregion
180
- export { type ArchicatConfig, type ArchicatConfigInput, type ArchicatDefinitionRootConfig, type ArchicatDependency, type ArchicatLibraryContract, type ArchicatLibraryInput, type ArchicatModuleContract, type ArchicatModuleInput, type ArchicatPrefixConfig, type ArchicatProjectGraph, defineArchicatConfig, defineLibrary, defineModule };
342
+ export { type ArchicatAliasConfig, type ArchicatAppContract, type ArchicatAppDependencies, type ArchicatAppDependency, type ArchicatAppInput, type ArchicatConfig, type ArchicatConfigInput, type ArchicatDefinitionRootConfig, type ArchicatLibraryApiDependencies, type ArchicatLibraryApiDependency, type ArchicatLibraryContract, type ArchicatLibraryImplDependencies, type ArchicatLibraryImplDependency, type ArchicatLibraryInput, type ArchicatModuleApiDependencies, type ArchicatModuleApiDependency, type ArchicatModuleContract, type ArchicatModuleImplDependencies, type ArchicatModuleImplDependency, type ArchicatModuleInput, type ArchicatPrefixConfig, type ArchicatSurfaceConfig, type ArchicatSurfaceContract, type ArchicatSurfaceInput, defineApp, defineArchicatConfig, defineLibrary, defineModule };
@@ -1,3 +1,79 @@
1
+ //#region src/configs/archicat-project-graph.d.ts
2
+ /**
3
+ * @description Generated dependency targets allowed in module API surfaces.
4
+ */
5
+ interface ArchicatModuleApiDependencies {}
6
+ /**
7
+ * @description Generated dependency targets allowed in module implementation surfaces.
8
+ */
9
+ interface ArchicatModuleImplDependencies {}
10
+ /**
11
+ * @description Generated dependency targets allowed in library API surfaces.
12
+ */
13
+ interface ArchicatLibraryApiDependencies {}
14
+ /**
15
+ * @description Generated dependency targets allowed in library implementation surfaces.
16
+ */
17
+ interface ArchicatLibraryImplDependencies {}
18
+ /**
19
+ * @description Generated dependency targets allowed in app composition roots.
20
+ */
21
+ interface ArchicatAppDependencies {}
22
+ /**
23
+ * @description Dependency key fallback used before `.archicat/types/graph.d.ts` exists.
24
+ */
25
+ type ArchicatDependencyKey<Dependencies> = keyof Dependencies extends never ? string : Extract<keyof Dependencies, string>;
26
+ /**
27
+ * @description Dependency target allowed from a module API surface.
28
+ */
29
+ type ArchicatModuleApiDependency = ArchicatDependencyKey<ArchicatModuleApiDependencies>;
30
+ /**
31
+ * @description Dependency target allowed from a module implementation surface.
32
+ */
33
+ type ArchicatModuleImplDependency = ArchicatDependencyKey<ArchicatModuleImplDependencies>;
34
+ /**
35
+ * @description Dependency target allowed from a library API surface.
36
+ */
37
+ type ArchicatLibraryApiDependency = ArchicatDependencyKey<ArchicatLibraryApiDependencies>;
38
+ /**
39
+ * @description Dependency target allowed from a library implementation surface.
40
+ */
41
+ type ArchicatLibraryImplDependency = ArchicatDependencyKey<ArchicatLibraryImplDependencies>;
42
+ /**
43
+ * @description Dependency target allowed from an app composition root.
44
+ */
45
+ type ArchicatAppDependency = ArchicatDependencyKey<ArchicatAppDependencies>;
46
+ //#endregion
47
+ //#region src/configs/app-config.d.ts
48
+ /**
49
+ * @description User-facing app composition definition input.
50
+ */
51
+ interface ArchicatAppInput {
52
+ /**
53
+ * @description Stable app name used in the Archicat project graph.
54
+ */
55
+ readonly name: string;
56
+ /**
57
+ * @description App source root, relative to the app definition file.
58
+ * @default The directory containing `archicat.app.ts`.
59
+ */
60
+ readonly root?: string;
61
+ /**
62
+ * @description Dependency targets visible from this app composition root.
63
+ * @default []
64
+ */
65
+ readonly dependencies?: readonly ArchicatAppDependency[];
66
+ }
67
+ /**
68
+ * @description Immutable app composition contract loaded by Archicat.
69
+ */
70
+ type ArchicatAppContract = Readonly<{
71
+ readonly kind: 'app';
72
+ readonly name: string;
73
+ readonly root?: string;
74
+ readonly dependencies: readonly ArchicatAppDependency[];
75
+ }>;
76
+ //#endregion
1
77
  //#region src/configs/archicat-config.d.ts
2
78
  /**
3
79
  * @description Definition discovery roots for one Archicat definition kind.
@@ -8,6 +84,49 @@ interface ArchicatDefinitionRootConfig {
8
84
  */
9
85
  readonly include?: readonly string[];
10
86
  }
87
+ /**
88
+ * @description TypeScript config fragment merged into generated `.archicat/tsconfig.json`.
89
+ */
90
+ interface ArchicatTypeScriptTsConfigInput {
91
+ /**
92
+ * @description Base TypeScript config extended by generated `.archicat/tsconfig.json`.
93
+ */
94
+ readonly extends?: string;
95
+ /**
96
+ * @description Project source files merged into generated `.archicat/tsconfig.json` include.
97
+ * Archicat rewrites relative paths to the generated config directory and appends generated type declarations automatically.
98
+ */
99
+ readonly include?: readonly string[];
100
+ /**
101
+ * @description Project paths merged into generated `.archicat/tsconfig.json` exclude.
102
+ * Archicat rewrites relative paths to the generated config directory.
103
+ */
104
+ readonly exclude?: readonly string[];
105
+ /**
106
+ * @description Project files merged into generated `.archicat/tsconfig.json` files.
107
+ * Archicat rewrites relative paths to the generated config directory.
108
+ */
109
+ readonly files?: readonly string[];
110
+ /**
111
+ * @description Unsupported. Put compiler options in the base or app tsconfig. Archicat owns generated `compilerOptions.paths` and does not support `baseUrl`.
112
+ */
113
+ readonly compilerOptions?: {
114
+ readonly paths?: never;
115
+ readonly baseUrl?: never;
116
+ };
117
+ }
118
+ /**
119
+ * @description TypeScript integration options used to generate `.archicat/tsconfig.json`.
120
+ */
121
+ interface ArchicatTypeScriptConfigInput {
122
+ /**
123
+ * @description Partial TypeScript config merged into generated `.archicat/tsconfig.json`.
124
+ * Archicat rewrites relative paths from the project root to `.archicat`, appends generated type declarations to `include`, and injects generated aliases into `compilerOptions.paths`.
125
+ * `compilerOptions` is not supported here. Put compiler policy in the base tsconfig and app build overrides in the app tsconfig.
126
+ * @default {}
127
+ */
128
+ readonly tsConfig?: ArchicatTypeScriptTsConfigInput;
129
+ }
11
130
  /**
12
131
  * @description TypeScript alias prefixes reserved by Archicat.
13
132
  */
@@ -23,6 +142,12 @@ interface ArchicatPrefixConfig {
23
142
  */
24
143
  readonly library?: string;
25
144
  }
145
+ /**
146
+ * @description User import aliases generated into `.archicat/tsconfig.json` together with Archicat module and library aliases.
147
+ * Aliases are resolved relative to the Archicat project root. Do not define TypeScript `compilerOptions.paths` manually for an Archicat project.
148
+ * @default {}
149
+ */
150
+ type ArchicatAliasConfig = Readonly<Record<string, string>>;
26
151
  /**
27
152
  * @description User-facing Archicat root config input.
28
153
  */
@@ -33,20 +158,20 @@ interface ArchicatConfigInput {
33
158
  */
34
159
  readonly root?: string;
35
160
  /**
36
- * @description Directory for generated mirror files and generated types.
161
+ * @description Directory for generated mirror files, generated types, and reports.
37
162
  * @default '.archicat'
38
163
  */
39
164
  readonly outDir?: string;
40
165
  /**
41
- * @description Directory for generated debug reports.
42
- * @default 'archicat-report'
166
+ * @description TypeScript integration options used to generate `.archicat/tsconfig.json`.
167
+ * @default {}
43
168
  */
44
- readonly reportDir?: string;
169
+ readonly typescript?: ArchicatTypeScriptConfigInput;
45
170
  /**
46
- * @description User tsconfig file to merge into the generated Archicat tsconfig.
47
- * @default Auto-detects tsconfig.base.json, then tsconfig.json.
171
+ * @description User TypeScript aliases generated by Archicat.
172
+ * @default {}
48
173
  */
49
- readonly tsconfig?: string;
174
+ readonly alias?: ArchicatAliasConfig;
50
175
  /**
51
176
  * @description Reserved TypeScript import prefixes generated by Archicat.
52
177
  * @default { module: '@module', library: '@library' }
@@ -62,6 +187,11 @@ interface ArchicatConfigInput {
62
187
  * @default { include: [] }
63
188
  */
64
189
  readonly libraries?: ArchicatDefinitionRootConfig;
190
+ /**
191
+ * @description App composition definition discovery config.
192
+ * @default { include: [] }
193
+ */
194
+ readonly apps?: ArchicatDefinitionRootConfig;
65
195
  }
66
196
  /**
67
197
  * @description Normalized immutable Archicat config contract.
@@ -69,8 +199,19 @@ interface ArchicatConfigInput {
69
199
  type ArchicatConfig = Readonly<{
70
200
  readonly root?: string;
71
201
  readonly outDir?: string;
72
- readonly reportDir?: string;
73
- readonly tsconfig?: string;
202
+ readonly typescript?: Readonly<{
203
+ readonly tsConfig?: Readonly<{
204
+ readonly extends?: string;
205
+ readonly include?: readonly string[];
206
+ readonly exclude?: readonly string[];
207
+ readonly files?: readonly string[];
208
+ readonly compilerOptions?: Readonly<{
209
+ readonly paths?: never;
210
+ readonly baseUrl?: never;
211
+ }>;
212
+ }>;
213
+ }>;
214
+ readonly alias?: ArchicatAliasConfig;
74
215
  readonly prefixes?: Readonly<{
75
216
  readonly module?: string;
76
217
  readonly library?: string;
@@ -81,17 +222,38 @@ type ArchicatConfig = Readonly<{
81
222
  readonly libraries?: Readonly<{
82
223
  readonly include?: readonly string[];
83
224
  }>;
225
+ readonly apps?: Readonly<{
226
+ readonly include?: readonly string[];
227
+ }>;
84
228
  }>;
85
229
  //#endregion
86
- //#region src/configs/archicat-project-graph.d.ts
230
+ //#region src/configs/surface-config.d.ts
231
+ /**
232
+ * @description Surface root shorthand or full surface config.
233
+ */
234
+ type ArchicatSurfaceInput<Dependency extends string> = string | ArchicatSurfaceConfig<Dependency>;
87
235
  /**
88
- * @description Generated Archicat project graph declaration surface.
236
+ * @description Source surface config.
89
237
  */
90
- interface ArchicatProjectGraph {}
238
+ interface ArchicatSurfaceConfig<Dependency extends string> {
239
+ /**
240
+ * @description Surface source root, relative to the definition file.
241
+ * @default Generates an empty mirror for the surface.
242
+ */
243
+ readonly root?: string;
244
+ /**
245
+ * @description Dependency targets visible from this surface.
246
+ * @default []
247
+ */
248
+ readonly dependencies?: readonly Dependency[];
249
+ }
91
250
  /**
92
- * @description Dependency reference from the generated Archicat project graph.
251
+ * @description Immutable normalized surface contract.
93
252
  */
94
- type ArchicatDependency = keyof ArchicatProjectGraph extends never ? string : keyof ArchicatProjectGraph;
253
+ type ArchicatSurfaceContract<Dependency extends string> = Readonly<{
254
+ readonly root?: string;
255
+ readonly dependencies: readonly Dependency[];
256
+ }>;
95
257
  //#endregion
96
258
  //#region src/configs/library-config.d.ts
97
259
  /**
@@ -99,28 +261,28 @@ type ArchicatDependency = keyof ArchicatProjectGraph extends never ? string : ke
99
261
  */
100
262
  interface ArchicatLibraryInput {
101
263
  /**
102
- * @description Stable library id used in the Archicat project graph.
264
+ * @description Stable library name used in the Archicat project graph.
103
265
  */
104
- readonly id: string;
266
+ readonly name: string;
105
267
  /**
106
- * @description Library public API root, relative to the library definition file.
268
+ * @description Library public API surface.
107
269
  * @default Generates an empty public API mirror.
108
270
  */
109
- readonly api?: string;
271
+ readonly api?: ArchicatSurfaceInput<ArchicatLibraryApiDependency>;
110
272
  /**
111
- * @description Public graph dependencies this library may import.
112
- * @default []
273
+ * @description Library implementation surface.
274
+ * @default Generates a no-op implementation mirror.
113
275
  */
114
- readonly dependencies?: readonly ArchicatDependency[];
276
+ readonly impl?: ArchicatSurfaceInput<ArchicatLibraryImplDependency>;
115
277
  }
116
278
  /**
117
279
  * @description Immutable library definition contract loaded by Archicat.
118
280
  */
119
281
  type ArchicatLibraryContract = Readonly<{
120
282
  readonly kind: 'library';
121
- readonly id: string;
122
- readonly api?: string;
123
- readonly dependencies: readonly ArchicatDependency[];
283
+ readonly name: string;
284
+ readonly api: ArchicatSurfaceContract<ArchicatLibraryApiDependency>;
285
+ readonly impl: ArchicatSurfaceContract<ArchicatLibraryImplDependency>;
124
286
  }>;
125
287
  //#endregion
126
288
  //#region src/configs/module-config.d.ts
@@ -129,36 +291,36 @@ type ArchicatLibraryContract = Readonly<{
129
291
  */
130
292
  interface ArchicatModuleInput {
131
293
  /**
132
- * @description Stable module id used in the Archicat project graph.
294
+ * @description Stable module name used in the Archicat project graph.
133
295
  */
134
- readonly id: string;
296
+ readonly name: string;
135
297
  /**
136
- * @description Module public API root, relative to the module definition file.
298
+ * @description Module public API surface.
137
299
  * @default Generates an empty public API mirror.
138
300
  */
139
- readonly api?: string;
301
+ readonly api?: ArchicatSurfaceInput<ArchicatModuleApiDependency>;
140
302
  /**
141
- * @description Module implementation root, relative to the module definition file.
303
+ * @description Module implementation surface.
142
304
  * @default Generates a no-op implementation mirror.
143
305
  */
144
- readonly impl?: string;
145
- /**
146
- * @description Public graph dependencies this module may import.
147
- * @default []
148
- */
149
- readonly dependencies?: readonly ArchicatDependency[];
306
+ readonly impl?: ArchicatSurfaceInput<ArchicatModuleImplDependency>;
150
307
  }
151
308
  /**
152
309
  * @description Immutable module definition contract loaded by Archicat.
153
310
  */
154
311
  type ArchicatModuleContract = Readonly<{
155
312
  readonly kind: 'module';
156
- readonly id: string;
157
- readonly api?: string;
158
- readonly impl?: string;
159
- readonly dependencies: readonly ArchicatDependency[];
313
+ readonly name: string;
314
+ readonly api: ArchicatSurfaceContract<ArchicatModuleApiDependency>;
315
+ readonly impl: ArchicatSurfaceContract<ArchicatModuleImplDependency>;
160
316
  }>;
161
317
  //#endregion
318
+ //#region src/configs/define-app-config.d.ts
319
+ /**
320
+ * @description Defines one Archicat app composition root.
321
+ */
322
+ declare function defineApp(app: ArchicatAppInput): ArchicatAppContract;
323
+ //#endregion
162
324
  //#region src/configs/define-archicat-config.d.ts
163
325
  /**
164
326
  * @description Defines the root Archicat config.
@@ -177,4 +339,4 @@ declare function defineLibrary(library: ArchicatLibraryInput): ArchicatLibraryCo
177
339
  */
178
340
  declare function defineModule(module: ArchicatModuleInput): ArchicatModuleContract;
179
341
  //#endregion
180
- export { type ArchicatConfig, type ArchicatConfigInput, type ArchicatDefinitionRootConfig, type ArchicatDependency, type ArchicatLibraryContract, type ArchicatLibraryInput, type ArchicatModuleContract, type ArchicatModuleInput, type ArchicatPrefixConfig, type ArchicatProjectGraph, defineArchicatConfig, defineLibrary, defineModule };
342
+ export { type ArchicatAliasConfig, type ArchicatAppContract, type ArchicatAppDependencies, type ArchicatAppDependency, type ArchicatAppInput, type ArchicatConfig, type ArchicatConfigInput, type ArchicatDefinitionRootConfig, type ArchicatLibraryApiDependencies, type ArchicatLibraryApiDependency, type ArchicatLibraryContract, type ArchicatLibraryImplDependencies, type ArchicatLibraryImplDependency, type ArchicatLibraryInput, type ArchicatModuleApiDependencies, type ArchicatModuleApiDependency, type ArchicatModuleContract, type ArchicatModuleImplDependencies, type ArchicatModuleImplDependency, type ArchicatModuleInput, type ArchicatPrefixConfig, type ArchicatSurfaceConfig, type ArchicatSurfaceContract, type ArchicatSurfaceInput, defineApp, defineArchicatConfig, defineLibrary, defineModule };
@@ -1 +1 @@
1
- function e(e={}){return Object.freeze({...e.root===void 0?{}:{root:e.root},...e.outDir===void 0?{}:{outDir:e.outDir},...e.reportDir===void 0?{}:{reportDir:e.reportDir},...e.tsconfig===void 0?{}:{tsconfig:e.tsconfig},...e.prefixes===void 0?{}:{prefixes:Object.freeze({...e.prefixes.module===void 0?{}:{module:e.prefixes.module},...e.prefixes.library===void 0?{}:{library:e.prefixes.library}})},...e.modules===void 0?{}:{modules:Object.freeze({...e.modules.include===void 0?{}:{include:Object.freeze([...e.modules.include])}})},...e.libraries===void 0?{}:{libraries:Object.freeze({...e.libraries.include===void 0?{}:{include:Object.freeze([...e.libraries.include])}})}})}function t(e){return Object.freeze({kind:`library`,id:e.id,...e.api===void 0?{}:{api:e.api},dependencies:Object.freeze([...e.dependencies??[]])})}function n(e){return Object.freeze({kind:`module`,id:e.id,...e.api===void 0?{}:{api:e.api},...e.impl===void 0?{}:{impl:e.impl},dependencies:Object.freeze([...e.dependencies??[]])})}export{e as defineArchicatConfig,t as defineLibrary,n as defineModule};
1
+ function e(e){return Object.freeze({kind:`app`,name:e.name,...e.root===void 0?{}:{root:e.root},dependencies:Object.freeze([...e.dependencies??[]])})}function t(e){let t={...e};for(let e of Object.keys(t))t[e]===void 0&&delete t[e];return Object.freeze(t)}function n(e={}){return t({root:e.root,outDir:e.outDir,typescript:e.typescript?r(e.typescript):void 0,alias:e.alias?Object.freeze({...e.alias}):void 0,prefixes:e.prefixes?a(e.prefixes):void 0,modules:e.modules?o(e.modules):void 0,libraries:e.libraries?o(e.libraries):void 0,apps:e.apps?o(e.apps):void 0})}function r(e){return t({tsConfig:e.tsConfig?i(e.tsConfig):void 0})}function i(e){return t({extends:e.extends,include:e.include?Object.freeze([...e.include]):void 0,exclude:e.exclude?Object.freeze([...e.exclude]):void 0,files:e.files?Object.freeze([...e.files]):void 0,compilerOptions:e.compilerOptions?Object.freeze({...e.compilerOptions}):void 0})}function a(e){return t({module:e.module,library:e.library})}function o(e){return t({include:e.include?Object.freeze([...e.include]):void 0})}function s(e){return typeof e==`string`?Object.freeze({root:e,dependencies:Object.freeze([])}):t({root:e?.root,dependencies:Object.freeze([...e?.dependencies??[]])})}function c(e){return Object.freeze({kind:`library`,name:e.name,api:s(e.api),impl:s(e.impl)})}function l(e){return Object.freeze({kind:`module`,name:e.name,api:s(e.api),impl:s(e.impl)})}export{e as defineApp,n as defineArchicatConfig,c as defineLibrary,l as defineModule};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archicat",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "M²: modular mirroring for clean architecture.",
5
5
  "keywords": [
6
6
  "m2",
@@ -56,5 +56,5 @@
56
56
  "publishConfig": {
57
57
  "registry": "https://registry.npmjs.org/"
58
58
  },
59
- "gitHead": "c17dd7ebf6530c88038a22113d7c6739a22550a9"
59
+ "gitHead": "557aec7d9b698eb46a1ab1e012afcf78394cbf91"
60
60
  }