archicat 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
- # ArchiCat
1
+ # Archicat
2
2
 
3
3
  **M²: Modular Mirroring.**
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 module mirror from your source code. Public APIs become aliases. Implementations stay private. The mirror is the boundary.
8
8
 
9
9
  ```bash
10
10
  npm i -D archicat
@@ -33,17 +33,17 @@ You define the module:
33
33
  import { defineModule } from 'archicat';
34
34
 
35
35
  export default defineModule({
36
- id: 'account',
36
+ id: 'media',
37
37
  api: './api',
38
38
  impl: './impl',
39
- dependencies: ['media'],
39
+ dependencies: ['module.account.api'],
40
40
  });
41
41
  ```
42
42
 
43
- ArchiCat mirrors it:
43
+ Archicat mirrors it:
44
44
 
45
45
  ```txt
46
- .archicat/modules/account/
46
+ .archicat/modules/media/
47
47
  api/
48
48
  impl/
49
49
  ```
@@ -51,13 +51,13 @@ ArchiCat mirrors it:
51
51
  You import the mirror:
52
52
 
53
53
  ```ts
54
- import { AccountReader } from '@account';
54
+ import { AccountReader } from '@module/account';
55
55
  ```
56
56
 
57
57
  Not the machinery:
58
58
 
59
59
  ```ts
60
- import { AccountRepository } from '@account/impl'; // does not exist
60
+ import { AccountRepository } from '@module/account/impl'; // does not exist
61
61
  import { AccountRepository } from '../../account/impl/repository'; // blocked
62
62
  ```
63
63
 
@@ -67,10 +67,8 @@ import { AccountRepository } from '../../account/impl/repository'; // blocked
67
67
  import { defineArchicatConfig } from 'archicat';
68
68
 
69
69
  export default defineArchicatConfig({
70
- root: '.',
71
- outDir: './.archicat',
72
70
  modules: {
73
- include: ['./src/modules/*/archicat.module.ts'],
71
+ include: ['./src/modules'],
74
72
  },
75
73
  });
76
74
  ```
@@ -80,10 +78,12 @@ export default defineArchicatConfig({
80
78
  ```txt
81
79
  .archicat/
82
80
  tsconfig.json
83
- manifest.json
84
81
  modules/
85
- generated/
86
- report/
82
+ types/
83
+
84
+ archicat-report/
85
+ build.json
86
+ graph.mmd
87
87
  ```
88
88
 
89
89
  Extend the generated config:
@@ -1,21 +1,14 @@
1
- import e from"node:path";import t from"node:fs";import{createJiti as n}from"jiti";import r from"typescript";async function i(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);return s(a,i),{configFilePath:i,rootDir:e.resolve(r,a.root),outDir:e.resolve(r,a.outDir),config:a}}async function a(t){let n=await o(t,e.dirname(t));return c(n,t),{contractFilePath:t,moduleDir:e.dirname(t),contract:n}}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,t){if(typeof e!=`object`||!e)throw Error(`Invalid ArchiCat config: ${t}`);let n=e;if(typeof n.root!=`string`||n.root.trim()===``)throw Error(`ArchiCat config must define a non-empty root string: ${t}`);if(typeof n.outDir!=`string`||n.outDir.trim()===``)throw Error(`ArchiCat config must define a non-empty outDir string: ${t}`);if(!n.modules||!Array.isArray(n.modules.include))throw Error(`ArchiCat config must define modules.include: ${t}`)}function c(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid ArchiCat module contract: ${t}`);let n=e;if(typeof n.id!=`string`||n.id.trim()===``)throw Error(`ArchiCat module must define a non-empty id: ${t}`);if(n.api!==void 0&&typeof n.api!=`string`)throw Error(`ArchiCat module api must be a string when defined: ${t}`);if(n.impl!==void 0&&typeof n.impl!=`string`)throw Error(`ArchiCat module impl must be a string when defined: ${t}`);if(!Array.isArray(n.dependencies))throw Error(`ArchiCat module dependencies must be an array: ${t}`)}function l(e,t){let n=t.flatMap(t=>u(e,t));return Array.from(new Set(n)).sort((e,t)=>e.localeCompare(t))}function u(n,r){let i=e.resolve(n,r);if(!i.includes(`*`))return t.existsSync(i)?[i]:[];let a=i.split(e.sep);if(a.filter(e=>e.includes(`*`)).length!==1)throw Error(`ArchiCat V1 supports exactly one wildcard segment per include pattern: ${r}`);let o=a.findIndex(e=>e.includes(`*`)),s=a.slice(0,o).join(e.sep)||e.sep,c=a[o]??`*`,l=a.slice(o+1),u=d(c);return t.existsSync(s)?t.readdirSync(s,{withFileTypes:!0}).filter(e=>e.isDirectory()).filter(e=>u.test(e.name)).map(t=>e.join(s,t.name,...l)).filter(e=>t.existsSync(e)&&t.statSync(e).isFile()):[]}function d(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function f(e,t){let n=t.map(t=>p(e.outDir,t));return g(n),ee(n),{rootDir:e.rootDir,outDir:e.outDir,configFilePath:e.configFilePath,modules:n}}function p(t,n){let{contract:r,contractFilePath:i,moduleDir:a}=n;h(r.id,i);let o=r.api?m(a,r.api,`api`,r.id):void 0,s=r.impl?m(a,r.impl,`impl`,r.id):void 0;return{id:r.id,alias:`@${r.id}`,dependencies:[...r.dependencies],contractFilePath:i,moduleDir:a,apiRootPath:o,implRootPath:s,mirrorApiRootPath:e.join(t,`modules`,r.id,`api`),mirrorImplRootPath:e.join(t,`modules`,r.id,`impl`)}}function m(n,r,i,a){let o=e.resolve(n,r);if(!t.existsSync(o))throw Error(`Module "${a}" declares ${i} root that does not exist: ${o}`);if(!t.statSync(o).isDirectory())throw Error(`Module "${a}" declares ${i} root that is not a directory: ${o}`);return o}function h(e,t){if(!/^[a-z][a-z0-9-]*$/u.test(e))throw Error(`Invalid ArchiCat module id "${e}" in ${t}. Use ^[a-z][a-z0-9-]*$`)}function g(e){let t=new Map;for(let n of e){let e=t.get(n.id);if(e)throw Error(`Duplicate ArchiCat module id "${n.id}" in ${e} and ${n.contractFilePath}`);t.set(n.id,n.contractFilePath)}}function ee(e){let t=new Set(e.map(e=>e.id));for(let n of e)for(let e of n.dependencies){if(e===n.id)throw Error(`Module "${n.id}" cannot depend on itself.`);if(!t.has(e))throw Error(`Module "${n.id}" declares unknown dependency "${e}".`)}}async function _(e){let t=await i(e),n=l(t.rootDir,t.config.modules.include);if(n.length===0)throw Error(`No ArchiCat module contracts matched modules.include.`);return f(t,await Promise.all(n.map(e=>a(e))))}function v(t){return t.split(e.sep).join(`/`)}function y(t,n){let r=e.dirname(t),i=e.parse(n),a=e.join(i.dir,i.name),o=v(e.relative(r,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function b(t,n){let r=e.relative(n,t);return r===``||!!r&&!r.startsWith(`..`)&&!e.isAbsolute(r)}function x(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function S(t,n){return v(e.relative(t,n))}function C(e){return t.existsSync(e)?t.statSync(e).isFile()?w(e)?[e]:[]:T(e).filter(w).sort((e,t)=>e.localeCompare(t)):[]}function w(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function T(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(...T(i));continue}t.isFile()&&r.push(i)}return r}function E(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 te(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(ne(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 ne(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 re(e){let t=await _(e);return[...ie(t),...M(t)]}function ie(e){let t=[],n=e.modules.flatMap(e=>ae(e));for(let r of n){let n=A(e.modules,r);if(n)for(let i of E(r)){let a=D(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function ae(e){return[...e.apiRootPath?C(e.apiRootPath):[],...e.implRootPath?C(e.implRootPath):[]]}function D(e,t,n,r){let i=j(e.modules,r);if(i)return i.id===t.id||t.dependencies.includes(i.id)?void 0:N(e,n,r,`Module "${t.id}" imports "${i.id}" but does not declare it in dependencies.`);if(!r.startsWith(`#archicat/`)&&(r.startsWith(`.`)||r.startsWith(`/`)))return O(e,t,n,r)}function O(e,t,n,r){let i=k(n,r),a=A(e.modules,i);if(!(!a||a.id===t.id))return N(e,n,r,`Module "${t.id}" imports module "${a.id}" through a source path. Use "${a.alias}" instead.`)}function k(t,n){return x(n.startsWith(`/`)?n:e.resolve(e.dirname(t),n))}function A(e,t){let n=x(t);return e.find(e=>[e.apiRootPath,e.implRootPath,e.moduleDir].filter(e=>!!e).some(e=>b(n,x(e))))}function j(e,t){return e.find(e=>t===e.alias||t.startsWith(`${e.alias}/`))}function M(e){let t=[],n=new Map(e.modules.map(e=>[e.id,e])),r=new Set,i=new Set,a=(o,s)=>{if(!i.has(o.id)){if(r.has(o.id)){t.push({filePath:S(e.rootDir,o.contractFilePath),importPath:o.id,message:`Cyclic ArchiCat module dependency detected: ${[...s,o.id].join(` -> `)}`});return}r.add(o.id);for(let e of o.dependencies){let t=n.get(e);t&&a(t,[...s,o.id])}r.delete(o.id),i.add(o.id)}};for(let t of e.modules)a(t,[]);return t}function N(e,t,n,r){return{filePath:S(e.rootDir,t),importPath:n,message:r}}async function P(e){let t=await _(e);return[...F(t),...I(t),...L(t)]}function F(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 I(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 L(n){let r=[];for(let i of n.modules){let n=e.join(i.moduleDir,`api`),a=e.join(i.moduleDir,`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}function R(e){t.existsSync(e)&&t.rmSync(e,{recursive:!0,force:!0}),t.mkdirSync(e,{recursive:!0})}function z(n,r){t.mkdirSync(e.dirname(n),{recursive:!0}),t.writeFileSync(n,r,`utf8`)}function B(e,t){z(e,`${JSON.stringify(t,null,2)}\n`)}function V(t){let n={modules:t.modules.map(e=>({id:e.id,dependencies:e.dependencies}))};B(e.join(t.outDir,`report`,`module-graph.json`),n),z(e.join(t.outDir,`report`,`module-graph.mmd`),oe(t))}function oe(e){let t=[`graph TD`];for(let n of e.modules){t.push(` ${H(n.id)}[${n.id}]`);for(let e of n.dependencies)t.push(` ${H(n.id)} --> ${H(e)}`)}return`${t.join(`
2
- `)}\n`}function H(e){return e.replace(/[^a-zA-Z0-9_]/gu,`_`)}function U(e){W(e),G(e)}function W(t){let n=`// Generated by ArchiCat. Do not edit.
3
- ${t.modules.map(e=>`import * as ${K(e.id)} from '../modules/${e.id}/impl/index.js';`).join(`
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 l(i,r);ne(a,i);let o=ee(a),s=e.resolve(r,o.root),c=e.resolve(s,o.outDir),u=e.resolve(s,o.reportDir),d=te(s,o.tsconfig);return{configFilePath:i,rootDir:s,outDir:c,reportDir:u,...d?{tsconfigPath:d}:{},config:a,resolvedConfig:o}}async function o(t){let n=await l(t,e.dirname(t));return u(n,t,`module`),{kind:`module`,contractFilePath:t,definitionDir:e.dirname(t),contract:n}}async function s(t){let n=await l(t,e.dirname(t));return u(n,t,`library`),{kind:`library`,contractFilePath:t,definitionDir:e.dirname(t),contract:n}}async function c(e,t){switch(t){case`module`:return o(e);case`library`:return s(e)}}async function l(e,t){return await n(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function ee(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 te(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 ne(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat config: ${t}`);let n=e;d(n.root,`root`,t),d(n.outDir,`outDir`,t),d(n.reportDir,`reportDir`,t),d(n.tsconfig,`tsconfig`,t),f(n.modules?.include,`modules.include`,t),f(n.libraries?.include,`libraries.include`,t),p(n.prefixes?.module,`prefixes.module`,t),p(n.prefixes?.library,`prefixes.library`,t)}function u(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${re(n)}(...): ${t}`);if(typeof r.id!=`string`||r.id.trim()===``)throw Error(`Archicat ${n} must define a non-empty id: ${t}`);if(d(r.api,`api`,t),n===`module`&&d(r.impl,`impl`,t),!Array.isArray(r.dependencies))throw Error(`Archicat ${n} dependencies must be an array: ${t}`)}function d(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 f(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 p(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 re(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function m(e,t,n){let r=t.flatMap(t=>ie(e,t,n));return Array.from(new Set(r)).sort((e,t)=>e.localeCompare(t))}function ie(n,r,i){let a=e.resolve(n,r);if(r.includes(`*`))return ae(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(se(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 ae(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=oe(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 oe(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function se(e){return[`node_modules`,`.git`,`.archicat`,`archicat-report`,`dist`,`build`,`coverage`].includes(e)}function ce(e,t){let n=t.filter(e=>e.kind===`module`).map(t=>le(e,t)),r=t.filter(e=>e.kind===`library`).map(t=>ue(e,t)),i=[...n,...r];de(i);let a=_(i);return fe(i,a.targets),pe(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 le(t,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;v(r.id,i,`module`);let o=r.api?g(a,r.api,`api`,r.id):void 0,s=r.impl?g(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 ue(t,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;v(r.id,i,`library`);let o=r.api?g(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 g(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 _(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,implicit:!1}))});return{targets:t,dependencies:[...e.filter(e=>e.kind===`module`).map(e=>({from:e.implTarget,to:e.apiTarget,implicit:!0})),...n]}}function v(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 de(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 fe(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(`${y(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(`${y(r)} cannot depend on itself: ${e}`)}}function pe(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 y(e){return`${e.kind} "${e.id}"`}async function b(e){let t=await a(e),n=m(t.rootDir,t.resolvedConfig.modules.include,`archicat.module.ts`),r=m(t.rootDir,t.resolvedConfig.libraries.include,`archicat.library.ts`);if(n.length===0)throw Error(`No Archicat module definitions matched modules.include.`);return ce(t,[...await Promise.all(n.map(e=>c(e,`module`))),...await Promise.all(r.map(e=>c(e,`library`)))])}function x(t){return t.split(e.sep).join(`/`)}function me(t,n){let r=e.dirname(t),i=e.parse(n),a=e.join(i.dir,i.name),o=x(e.relative(r,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function he(t,n){let r=e.relative(n,t);return r===``||!!r&&!r.startsWith(`..`)&&!e.isAbsolute(r)}function S(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function C(t,n){return x(e.relative(t,n))}function w(e){return t.existsSync(e)?t.statSync(e).isFile()?T(e)?[e]:[]:E(e).filter(T).sort((e,t)=>e.localeCompare(t)):[]}function T(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function E(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(...E(i));continue}t.isFile()&&r.push(i)}return r}function D(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 O(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(k(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 k(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 A(e){return j(await b(e))}function j(e){let t=[],n=e.definitions.flatMap(e=>M(e));for(let r of n){let n=I(e.definitions,r);if(n)for(let i of D(r)){let a=N(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function M(e){return e.kind===`module`?[...e.apiRootPath?w(e.apiRootPath):[],...e.implRootPath?w(e.implRootPath):[]]:e.apiRootPath?w(e.apiRootPath):[]}function N(e,t,n,r){let i=R(e,r);if(i)return i.kind===t.kind&&i.id===t.id||t.dependencies.includes(i.target)?void 0:z(e,n,r,`${B(t.kind)} "${t.id}" imports "${i.target}" but does not declare it in dependencies.`);if(r.startsWith(`.`)||r.startsWith(`/`))return P(e,t,n,r)}function P(e,t,n,r){let i=F(n,r),a=I(e.definitions,i);if(!(!a||a.kind===t.kind&&a.id===t.id))return z(e,n,r,`${B(t.kind)} "${t.id}" imports ${a.kind} "${a.id}" through a source path. Use "${a.alias}" instead.`)}function F(t,n){return S(n.startsWith(`/`)?n:e.resolve(e.dirname(t),n))}function I(e,t){let n=S(t);return e.find(e=>L(e).filter(e=>!!e).some(e=>he(n,S(e))))}function L(e){return e.kind===`module`?[e.apiRootPath,e.implRootPath,e.definitionDir]:[e.apiRootPath,e.definitionDir]}function R(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 z(e,t,n,r){return{filePath:C(e.rootDir,t),importPath:n,message:r}}function B(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}async function ge(e){let t=await b(e);return[..._e(t),...ve(t),...ye(t)]}function _e(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 ve(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 ye(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}function V(e){t.existsSync(e)&&t.rmSync(e,{recursive:!0,force:!0}),t.mkdirSync(e,{recursive:!0})}function H(n,r){t.mkdirSync(e.dirname(n),{recursive:!0}),t.writeFileSync(n,r,`utf8`)}function U(e,t){H(e,`${JSON.stringify(t,null,2)}\n`)}function W(t){let n=`declare module 'archicat' {
2
+ interface ArchicatProjectGraph {
3
+ ${t.graph.targets.map(e=>` '${e.key}': true;`).join(`
4
4
  `)}
5
-
6
- export const ArchicatModules = [
7
- ${t.modules.map(e=>` { id: '${e.id}', implementation: ${K(e.id)} },`).join(`
8
- `)}
9
- ] as const;
10
- `;z(e.join(t.outDir,`generated`,`modules.ts`),n)}function G(t){z(e.join(t.outDir,`generated`,`composition.ts`),`// Generated by ArchiCat. Do not edit.
11
- import { ArchicatModules } from './modules.js';
12
-
13
- export { ArchicatModules };
14
-
15
- export function getArchicatModules() {
16
- return ArchicatModules;
5
+ }
17
6
  }
18
- `)}function K(e){return`${e.replace(/-([a-z0-9])/gu,(e,t)=>t.toUpperCase())}Implementation`}function q(t){let n={generatedBy:`archicat`,version:1,rootDir:t.rootDir,outDir:t.outDir,modules:t.modules.map(e=>({id:e.id,alias:e.alias,dependencies:e.dependencies,contractFilePath:S(t.rootDir,e.contractFilePath),moduleDir:S(t.rootDir,e.moduleDir),...e.apiRootPath?{apiRootPath:S(t.rootDir,e.apiRootPath)}:{},...e.implRootPath?{implRootPath:S(t.rootDir,e.implRootPath)}:{},mirrorApiRootPath:S(t.rootDir,e.mirrorApiRootPath),mirrorImplRootPath:S(t.rootDir,e.mirrorImplRootPath)}))};return B(e.join(t.outDir,`manifest.json`),n),n}function se(e){for(let t of e)ce(t),le(t)}function ce(t){if(!t.apiRootPath){z(e.join(t.mirrorApiRootPath,`index.ts`),`${Y(`empty api`)}export {};\n`);return}let n=C(t.apiRootPath),r=new Set;for(let i of n){let n=v(e.relative(t.apiRootPath,i));r.add(n),J(e.join(t.mirrorApiRootPath,n),i)}r.has(`index.ts`)||z(e.join(t.mirrorApiRootPath,`index.ts`),`${Y(`empty api index`)}export {};\n`)}function le(t){let n=t.implRootPath?ue(t.implRootPath):void 0;if(!n){let n=`${Y(`empty impl`)}
7
+
8
+ export {};
9
+ `;H(e.join(t.outDir,`types`,`graph.d.ts`),n)}function be(e){for(let t of e)switch(t.kind){case`module`:xe(t);break;case`library`:G(t);break}}function xe(e){G(e),Se(e)}function G(t){if(!t.apiRootPath){H(e.join(t.mirrorApiRootPath,`index.ts`),`${q()}export {};
10
+ `);return}let n=w(t.apiRootPath),r=new Set;for(let i of n){let n=x(e.relative(t.apiRootPath,i));r.add(n),K(e.join(t.mirrorApiRootPath,n),i)}r.has(`index.ts`)||H(e.join(t.mirrorApiRootPath,`index.ts`),`${q()}export {};
11
+ `)}function Se(t){let n=t.implRootPath?Ce(t.implRootPath):void 0;if(!n){let n=`${q()}
19
12
  export const ArchicatModuleImplementation = {
20
13
  id: '${t.id}',
21
14
  assemblies: [],
@@ -24,7 +17,9 @@ export const ArchicatModuleImplementation = {
24
17
  } as const;
25
18
 
26
19
  export default ArchicatModuleImplementation;
27
- `;z(e.join(t.mirrorImplRootPath,`index.ts`),n);return}J(e.join(t.mirrorImplRootPath,`index.ts`),n)}function J(e,t){let n=y(e,t),r=te(t)?`export { default } from '${n}';\n`:``;z(e,`${Y(`mirror`)}
20
+ `;H(e.join(t.mirrorImplRootPath,`index.ts`),n);return}K(e.join(t.mirrorImplRootPath,`index.ts`),n)}function K(e,t){let n=me(e,t),r=O(t)?`export { default } from '${n}';\n`:``;H(e,`${q()}
28
21
  export * from '${n}';
29
- ${r}`)}function ue(t){for(let n of[`index.ts`,`index.mts`,`index.cts`,`index.tsx`]){let r=e.join(t,n);if(C(r).length>0)return r}}function Y(e){return`// Generated by ArchiCat (${e}). Do not edit.\n`}function de(n){let r={"#archicat/*":[`.archicat/generated/*`]};for(let t of n.modules)r[t.alias]=[v(e.relative(n.rootDir,e.join(t.mirrorApiRootPath,`index.ts`)))],r[`${t.alias}/*`]=[v(e.relative(n.rootDir,e.join(t.mirrorApiRootPath,`*`)))];let i=e.join(n.rootDir,`tsconfig.base.json`),a=t.existsSync(i)?`../tsconfig.base.json`:void 0,o={...a?{extends:a}:{},compilerOptions:{baseUrl:`..`,paths:r},include:[`../src/**/*.ts`,`./**/*.ts`],exclude:[`../node_modules`,`../dist`]};B(e.join(n.outDir,`tsconfig.json`),o)}async function X(t){let n=await _(t);if(e.resolve(n.outDir)===e.resolve(n.rootDir))throw Error(`ArchiCat outDir cannot be the project root.`);return R(n.outDir),se(n.modules),de(n),q(n),U(n),V(n),n}async function fe(e=process.argv.slice(2)){let[t,...n]=e,r=pe(n);try{switch(t){case`generate`:{let e=await X(r.config);Q(`Generated ${e.modules.length} module(s) into ${e.outDir}`);return}case`check`:{let e=await re(r.config);if(e.length===0){Q(`Architecture check passed.`);return}for(let t of e)$(`${t.filePath}\n import: ${t.importPath}\n ${t.message}`);process.exitCode=1;return}case`graph`:Q(`Generated graph for ${(await X(r.config)).modules.length} module(s).`);return;case`doctor`:{let e=await P(r.config);if(e.length===0){Q(`Doctor found no issues.`);return}for(let t of e){if(t.severity===`error`){$(t.message);continue}me(t.message)}return}case`help`:case`--help`:case`-h`:case void 0:Z();return;default:$(`Unknown command: ${t}`),Z(),process.exitCode=1}}catch(e){$(e instanceof Error?e.message:String(e)),process.exitCode=1}}function pe(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 Z(){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(`
30
- `))}function Q(e){console.log(`✓ ${e}`)}function me(e){console.warn(`! ${e}`)}function $(e){console.error(`✗ ${e}`)}export{fe as runMain};
22
+ ${r}`)}function Ce(t){for(let n of[`index.ts`,`index.mts`,`index.cts`,`index.tsx`]){let r=e.join(t,n);if(w(r).length>0)return r}}function q(){return`// Mirrored by Archicat.
23
+ `}function we(t){let n=Te(t);U(e.join(t.reportDir,`build.json`),n),H(e.join(t.reportDir,`graph.mmd`),De(t))}function Te(e){return{generatedBy:`archicat`,schemaVersion:1,prefixes:e.config.prefixes,targets:e.graph.targets.map(e=>e.key),definitions:e.definitions.map(t=>Ee(e,t)),dependencies:e.graph.dependencies}}function Ee(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:C(e.rootDir,t.contractFilePath),source:{root:C(e.rootDir,t.definitionDir),api:t.apiRootPath?C(e.rootDir,t.apiRootPath):void 0,impl:t.implRootPath?C(e.rootDir,t.implRootPath):void 0},mirror:{api:C(e.rootDir,t.mirrorApiRootPath),impl:C(e.rootDir,t.mirrorImplRootPath)}}:{kind:t.kind,id:t.id,targets:{api:t.apiTarget},aliases:{api:t.alias},dependencies:t.dependencies,contractFilePath:C(e.rootDir,t.contractFilePath),source:{root:C(e.rootDir,t.definitionDir),api:t.apiRootPath?C(e.rootDir,t.apiRootPath):void 0},mirror:{api:C(e.rootDir,t.mirrorApiRootPath)}}}function De(e){let t=[`graph TD`];for(let n of e.graph.targets)t.push(` ${J(n.key)}[${n.key}]`);for(let n of e.graph.dependencies){let e=n.implicit?`-.->`:`-->`;t.push(` ${J(n.from)} ${e} ${J(n.to)}`)}return`${t.join(`
24
+ `)}\n`}function J(e){return e.replace(/[^a-zA-Z0-9_]/gu,`_`)}function Oe(t){let n=je(t.tsconfigPath?Ae(t.tsconfigPath):{}),r=Me(n),i=ke(t);Ie(t,r,i);let a={compilerOptions:{...Fe(t,Re(n,[`baseUrl`,`paths`])),paths:{...Ne(t,r),...i}},include:[`../src/**/*.ts`,`./**/*.ts`,`./types/**/*.d.ts`],exclude:[`../node_modules`,`../dist`]};U(e.join(t.outDir,`tsconfig.json`),a)}function ke(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 Ae(e){let n=t.readFileSync(e,`utf8`);return JSON.parse(Le(n))}function je(e){let t=e.compilerOptions;return t&&typeof t==`object`&&!Array.isArray(t)?t:{}}function Me(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 Ne(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=>Pe(t.outDir,r,e));return i}function Pe(t,n,r){return e.isAbsolute(r)?Y(t,r):Y(t,e.resolve(n,r))}function Fe(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=x(e.relative(t,n));return r.startsWith(`.`)||(r=`./${r}`),r}function Ie(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 Le(e){return e.replace(/\/\*[\s\S]*?\*\//gu,``).replace(/(^|[^:])\/\/.*$/gmu,`$1`)}function Re(e,t){let n={...e};for(let e of t)delete n[e];return n}async function X(t){let n=await b(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 V(n.outDir),V(n.reportDir),be(n.definitions),W(n),Oe(n),we(n),n}async function ze(e=process.argv.slice(2)){let[t,...n]=e,r=Be(n);try{switch(t){case`generate`:{let e=await X(r.config);Q(`Generated ${e.modules.length} module(s) into ${e.outDir}`);return}case`check`:{let e=await A(r.config);if(e.length===0){Q(`Architecture check passed.`);return}for(let t of e)$(`${t.filePath}\n import: ${t.importPath}\n ${t.message}`);process.exitCode=1;return}case`graph`:Q(`Generated graph for ${(await X(r.config)).modules.length} module(s).`);return;case`doctor`:{let e=await ge(r.config);if(e.length===0){Q(`Doctor found no issues.`);return}for(let t of e){if(t.severity===`error`){$(t.message);continue}Ve(t.message)}return}case`help`:case`--help`:case`-h`:case void 0:Z();return;default:$(`Unknown command: ${t}`),Z(),process.exitCode=1}}catch(e){$(e instanceof Error?e.message:String(e)),process.exitCode=1}}function Be(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 Z(){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(`
25
+ `))}function Q(e){console.log(`✓ ${e}`)}function Ve(e){console.warn(`! ${e}`)}function $(e){console.error(`✗ ${e}`)}export{ze as runMain};
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){return Object.freeze({root:e.root,outDir:e.outDir,modules:Object.freeze({include:Object.freeze([...e.modules.include])})})}function t(e){return Object.freeze({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.defineModule=t;
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,32 +1,180 @@
1
- //#region src/definition.d.ts
2
- interface ArchicatModuleRootConfig {
3
- include: readonly string[];
1
+ //#region src/configs/archicat-config.d.ts
2
+ /**
3
+ * @description Definition discovery roots for one Archicat definition kind.
4
+ */
5
+ interface ArchicatDefinitionRootConfig {
6
+ /**
7
+ * @description Directories or files where Archicat searches for matching definition marker files.
8
+ */
9
+ readonly include?: readonly string[];
4
10
  }
11
+ /**
12
+ * @description TypeScript alias prefixes reserved by Archicat.
13
+ */
14
+ interface ArchicatPrefixConfig {
15
+ /**
16
+ * @description Prefix for module public API aliases.
17
+ * @default '@module'
18
+ */
19
+ readonly module?: string;
20
+ /**
21
+ * @description Prefix for library public API aliases.
22
+ * @default '@library'
23
+ */
24
+ readonly library?: string;
25
+ }
26
+ /**
27
+ * @description User-facing Archicat root config input.
28
+ */
5
29
  interface ArchicatConfigInput {
6
- root: string;
7
- outDir: string;
8
- modules: ArchicatModuleRootConfig;
30
+ /**
31
+ * @description Project root directory.
32
+ * @default '.'
33
+ */
34
+ readonly root?: string;
35
+ /**
36
+ * @description Directory for generated mirror files and generated types.
37
+ * @default '.archicat'
38
+ */
39
+ readonly outDir?: string;
40
+ /**
41
+ * @description Directory for generated debug reports.
42
+ * @default 'archicat-report'
43
+ */
44
+ readonly reportDir?: string;
45
+ /**
46
+ * @description User tsconfig file to merge into the generated Archicat tsconfig.
47
+ * @default Auto-detects tsconfig.base.json, then tsconfig.json.
48
+ */
49
+ readonly tsconfig?: string;
50
+ /**
51
+ * @description Reserved TypeScript import prefixes generated by Archicat.
52
+ * @default { module: '@module', library: '@library' }
53
+ */
54
+ readonly prefixes?: ArchicatPrefixConfig;
55
+ /**
56
+ * @description Module definition discovery config.
57
+ * @default { include: ['./src/modules'] }
58
+ */
59
+ readonly modules?: ArchicatDefinitionRootConfig;
60
+ /**
61
+ * @description Library definition discovery config.
62
+ * @default { include: [] }
63
+ */
64
+ readonly libraries?: ArchicatDefinitionRootConfig;
9
65
  }
66
+ /**
67
+ * @description Normalized immutable Archicat config contract.
68
+ */
10
69
  type ArchicatConfig = Readonly<{
11
- root: string;
12
- outDir: string;
13
- modules: Readonly<{
14
- include: readonly string[];
70
+ readonly root?: string;
71
+ readonly outDir?: string;
72
+ readonly reportDir?: string;
73
+ readonly tsconfig?: string;
74
+ readonly prefixes?: Readonly<{
75
+ readonly module?: string;
76
+ readonly library?: string;
77
+ }>;
78
+ readonly modules?: Readonly<{
79
+ readonly include?: readonly string[];
80
+ }>;
81
+ readonly libraries?: Readonly<{
82
+ readonly include?: readonly string[];
15
83
  }>;
16
84
  }>;
85
+ //#endregion
86
+ //#region src/configs/archicat-project-graph.d.ts
87
+ /**
88
+ * @description Generated Archicat project graph declaration surface.
89
+ */
90
+ interface ArchicatProjectGraph {}
91
+ /**
92
+ * @description Dependency reference from the generated Archicat project graph.
93
+ */
94
+ type ArchicatDependency = keyof ArchicatProjectGraph extends never ? string : keyof ArchicatProjectGraph;
95
+ //#endregion
96
+ //#region src/configs/library-config.d.ts
97
+ /**
98
+ * @description User-facing library definition input.
99
+ */
100
+ interface ArchicatLibraryInput {
101
+ /**
102
+ * @description Stable library id used in the Archicat project graph.
103
+ */
104
+ readonly id: string;
105
+ /**
106
+ * @description Library public API root, relative to the library definition file.
107
+ * @default Generates an empty public API mirror.
108
+ */
109
+ readonly api?: string;
110
+ /**
111
+ * @description Public graph dependencies this library may import.
112
+ * @default []
113
+ */
114
+ readonly dependencies?: readonly ArchicatDependency[];
115
+ }
116
+ /**
117
+ * @description Immutable library definition contract loaded by Archicat.
118
+ */
119
+ type ArchicatLibraryContract = Readonly<{
120
+ readonly kind: 'library';
121
+ readonly id: string;
122
+ readonly api?: string;
123
+ readonly dependencies: readonly ArchicatDependency[];
124
+ }>;
125
+ //#endregion
126
+ //#region src/configs/module-config.d.ts
127
+ /**
128
+ * @description User-facing module definition input.
129
+ */
17
130
  interface ArchicatModuleInput {
18
- id: string;
19
- api?: string;
20
- impl?: string;
21
- dependencies?: readonly string[];
131
+ /**
132
+ * @description Stable module id used in the Archicat project graph.
133
+ */
134
+ readonly id: string;
135
+ /**
136
+ * @description Module public API root, relative to the module definition file.
137
+ * @default Generates an empty public API mirror.
138
+ */
139
+ readonly api?: string;
140
+ /**
141
+ * @description Module implementation root, relative to the module definition file.
142
+ * @default Generates a no-op implementation mirror.
143
+ */
144
+ readonly impl?: string;
145
+ /**
146
+ * @description Public graph dependencies this module may import.
147
+ * @default []
148
+ */
149
+ readonly dependencies?: readonly ArchicatDependency[];
22
150
  }
151
+ /**
152
+ * @description Immutable module definition contract loaded by Archicat.
153
+ */
23
154
  type ArchicatModuleContract = Readonly<{
24
- id: string;
25
- api?: string;
26
- impl?: string;
27
- dependencies: readonly string[];
155
+ readonly kind: 'module';
156
+ readonly id: string;
157
+ readonly api?: string;
158
+ readonly impl?: string;
159
+ readonly dependencies: readonly ArchicatDependency[];
28
160
  }>;
29
- declare function defineArchicatConfig(config: ArchicatConfigInput): ArchicatConfig;
161
+ //#endregion
162
+ //#region src/configs/define-archicat-config.d.ts
163
+ /**
164
+ * @description Defines the root Archicat config.
165
+ */
166
+ declare function defineArchicatConfig(config?: ArchicatConfigInput): ArchicatConfig;
167
+ //#endregion
168
+ //#region src/configs/define-library-config.d.ts
169
+ /**
170
+ * @description Defines one Archicat library.
171
+ */
172
+ declare function defineLibrary(library: ArchicatLibraryInput): ArchicatLibraryContract;
173
+ //#endregion
174
+ //#region src/configs/define-module-config.d.ts
175
+ /**
176
+ * @description Defines one Archicat module.
177
+ */
30
178
  declare function defineModule(module: ArchicatModuleInput): ArchicatModuleContract;
31
179
  //#endregion
32
- export { type ArchicatConfig, type ArchicatConfigInput, type ArchicatModuleContract, type ArchicatModuleInput, type ArchicatModuleRootConfig, defineArchicatConfig, defineModule };
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 };
@@ -1,32 +1,180 @@
1
- //#region src/definition.d.ts
2
- interface ArchicatModuleRootConfig {
3
- include: readonly string[];
1
+ //#region src/configs/archicat-config.d.ts
2
+ /**
3
+ * @description Definition discovery roots for one Archicat definition kind.
4
+ */
5
+ interface ArchicatDefinitionRootConfig {
6
+ /**
7
+ * @description Directories or files where Archicat searches for matching definition marker files.
8
+ */
9
+ readonly include?: readonly string[];
4
10
  }
11
+ /**
12
+ * @description TypeScript alias prefixes reserved by Archicat.
13
+ */
14
+ interface ArchicatPrefixConfig {
15
+ /**
16
+ * @description Prefix for module public API aliases.
17
+ * @default '@module'
18
+ */
19
+ readonly module?: string;
20
+ /**
21
+ * @description Prefix for library public API aliases.
22
+ * @default '@library'
23
+ */
24
+ readonly library?: string;
25
+ }
26
+ /**
27
+ * @description User-facing Archicat root config input.
28
+ */
5
29
  interface ArchicatConfigInput {
6
- root: string;
7
- outDir: string;
8
- modules: ArchicatModuleRootConfig;
30
+ /**
31
+ * @description Project root directory.
32
+ * @default '.'
33
+ */
34
+ readonly root?: string;
35
+ /**
36
+ * @description Directory for generated mirror files and generated types.
37
+ * @default '.archicat'
38
+ */
39
+ readonly outDir?: string;
40
+ /**
41
+ * @description Directory for generated debug reports.
42
+ * @default 'archicat-report'
43
+ */
44
+ readonly reportDir?: string;
45
+ /**
46
+ * @description User tsconfig file to merge into the generated Archicat tsconfig.
47
+ * @default Auto-detects tsconfig.base.json, then tsconfig.json.
48
+ */
49
+ readonly tsconfig?: string;
50
+ /**
51
+ * @description Reserved TypeScript import prefixes generated by Archicat.
52
+ * @default { module: '@module', library: '@library' }
53
+ */
54
+ readonly prefixes?: ArchicatPrefixConfig;
55
+ /**
56
+ * @description Module definition discovery config.
57
+ * @default { include: ['./src/modules'] }
58
+ */
59
+ readonly modules?: ArchicatDefinitionRootConfig;
60
+ /**
61
+ * @description Library definition discovery config.
62
+ * @default { include: [] }
63
+ */
64
+ readonly libraries?: ArchicatDefinitionRootConfig;
9
65
  }
66
+ /**
67
+ * @description Normalized immutable Archicat config contract.
68
+ */
10
69
  type ArchicatConfig = Readonly<{
11
- root: string;
12
- outDir: string;
13
- modules: Readonly<{
14
- include: readonly string[];
70
+ readonly root?: string;
71
+ readonly outDir?: string;
72
+ readonly reportDir?: string;
73
+ readonly tsconfig?: string;
74
+ readonly prefixes?: Readonly<{
75
+ readonly module?: string;
76
+ readonly library?: string;
77
+ }>;
78
+ readonly modules?: Readonly<{
79
+ readonly include?: readonly string[];
80
+ }>;
81
+ readonly libraries?: Readonly<{
82
+ readonly include?: readonly string[];
15
83
  }>;
16
84
  }>;
85
+ //#endregion
86
+ //#region src/configs/archicat-project-graph.d.ts
87
+ /**
88
+ * @description Generated Archicat project graph declaration surface.
89
+ */
90
+ interface ArchicatProjectGraph {}
91
+ /**
92
+ * @description Dependency reference from the generated Archicat project graph.
93
+ */
94
+ type ArchicatDependency = keyof ArchicatProjectGraph extends never ? string : keyof ArchicatProjectGraph;
95
+ //#endregion
96
+ //#region src/configs/library-config.d.ts
97
+ /**
98
+ * @description User-facing library definition input.
99
+ */
100
+ interface ArchicatLibraryInput {
101
+ /**
102
+ * @description Stable library id used in the Archicat project graph.
103
+ */
104
+ readonly id: string;
105
+ /**
106
+ * @description Library public API root, relative to the library definition file.
107
+ * @default Generates an empty public API mirror.
108
+ */
109
+ readonly api?: string;
110
+ /**
111
+ * @description Public graph dependencies this library may import.
112
+ * @default []
113
+ */
114
+ readonly dependencies?: readonly ArchicatDependency[];
115
+ }
116
+ /**
117
+ * @description Immutable library definition contract loaded by Archicat.
118
+ */
119
+ type ArchicatLibraryContract = Readonly<{
120
+ readonly kind: 'library';
121
+ readonly id: string;
122
+ readonly api?: string;
123
+ readonly dependencies: readonly ArchicatDependency[];
124
+ }>;
125
+ //#endregion
126
+ //#region src/configs/module-config.d.ts
127
+ /**
128
+ * @description User-facing module definition input.
129
+ */
17
130
  interface ArchicatModuleInput {
18
- id: string;
19
- api?: string;
20
- impl?: string;
21
- dependencies?: readonly string[];
131
+ /**
132
+ * @description Stable module id used in the Archicat project graph.
133
+ */
134
+ readonly id: string;
135
+ /**
136
+ * @description Module public API root, relative to the module definition file.
137
+ * @default Generates an empty public API mirror.
138
+ */
139
+ readonly api?: string;
140
+ /**
141
+ * @description Module implementation root, relative to the module definition file.
142
+ * @default Generates a no-op implementation mirror.
143
+ */
144
+ readonly impl?: string;
145
+ /**
146
+ * @description Public graph dependencies this module may import.
147
+ * @default []
148
+ */
149
+ readonly dependencies?: readonly ArchicatDependency[];
22
150
  }
151
+ /**
152
+ * @description Immutable module definition contract loaded by Archicat.
153
+ */
23
154
  type ArchicatModuleContract = Readonly<{
24
- id: string;
25
- api?: string;
26
- impl?: string;
27
- dependencies: readonly string[];
155
+ readonly kind: 'module';
156
+ readonly id: string;
157
+ readonly api?: string;
158
+ readonly impl?: string;
159
+ readonly dependencies: readonly ArchicatDependency[];
28
160
  }>;
29
- declare function defineArchicatConfig(config: ArchicatConfigInput): ArchicatConfig;
161
+ //#endregion
162
+ //#region src/configs/define-archicat-config.d.ts
163
+ /**
164
+ * @description Defines the root Archicat config.
165
+ */
166
+ declare function defineArchicatConfig(config?: ArchicatConfigInput): ArchicatConfig;
167
+ //#endregion
168
+ //#region src/configs/define-library-config.d.ts
169
+ /**
170
+ * @description Defines one Archicat library.
171
+ */
172
+ declare function defineLibrary(library: ArchicatLibraryInput): ArchicatLibraryContract;
173
+ //#endregion
174
+ //#region src/configs/define-module-config.d.ts
175
+ /**
176
+ * @description Defines one Archicat module.
177
+ */
30
178
  declare function defineModule(module: ArchicatModuleInput): ArchicatModuleContract;
31
179
  //#endregion
32
- export { type ArchicatConfig, type ArchicatConfigInput, type ArchicatModuleContract, type ArchicatModuleInput, type ArchicatModuleRootConfig, defineArchicatConfig, defineModule };
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 };
@@ -1 +1 @@
1
- function e(e){return Object.freeze({root:e.root,outDir:e.outDir,modules:Object.freeze({include:Object.freeze([...e.modules.include])})})}function t(e){return Object.freeze({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 defineModule};
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archicat",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
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": "4a6db6ef9c4a76049f668acc206a01f924c548e7"
59
+ "gitHead": "46d57e399e6b70f3dce13126ecf4a74f852093b2"
60
60
  }