archicat 0.0.3 → 0.0.5
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 +13 -14
- package/dist/cli/index.mjs +13 -19
- package/dist/src/index.cjs +1 -1
- package/dist/src/index.d.cts +168 -20
- package/dist/src/index.d.mts +168 -20
- package/dist/src/index.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Archicat
|
|
2
2
|
|
|
3
3
|
**M²: Modular Mirroring.**
|
|
4
4
|
|
|
5
5
|
The generative architecture framework for clean architecture.
|
|
6
6
|
|
|
7
|
-
|
|
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: '
|
|
36
|
+
id: 'media',
|
|
37
37
|
api: './api',
|
|
38
38
|
impl: './impl',
|
|
39
|
-
dependencies: ['
|
|
39
|
+
dependencies: ['module.account.api'],
|
|
40
40
|
});
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Archicat mirrors it:
|
|
44
44
|
|
|
45
45
|
```txt
|
|
46
|
-
.archicat/modules/
|
|
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
|
|
71
|
+
include: ['./src/modules'],
|
|
74
72
|
},
|
|
75
73
|
});
|
|
76
74
|
```
|
|
@@ -80,10 +78,11 @@ export default defineArchicatConfig({
|
|
|
80
78
|
```txt
|
|
81
79
|
.archicat/
|
|
82
80
|
tsconfig.json
|
|
83
|
-
manifest.json
|
|
84
81
|
modules/
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
types/
|
|
83
|
+
|
|
84
|
+
archicat-report/
|
|
85
|
+
build.json
|
|
87
86
|
```
|
|
88
87
|
|
|
89
88
|
Extend the generated config:
|
package/dist/cli/index.mjs
CHANGED
|
@@ -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
|
-
|
|
3
|
-
${t.
|
|
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
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
|
-
|
|
7
|
+
|
|
8
|
+
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()}
|
|
19
12
|
export const ArchicatModuleImplementation = {
|
|
20
13
|
id: '${t.id}',
|
|
21
14
|
assemblies: [],
|
|
@@ -24,7 +17,8 @@ export const ArchicatModuleImplementation = {
|
|
|
24
17
|
} as const;
|
|
25
18
|
|
|
26
19
|
export default ArchicatModuleImplementation;
|
|
27
|
-
`;
|
|
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
21
|
export * from '${n}';
|
|
29
|
-
${r}`)}function
|
|
30
|
-
`))}function
|
|
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};
|
package/dist/src/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){return Object.freeze({root:e.root
|
|
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;
|
package/dist/src/index.d.cts
CHANGED
|
@@ -1,32 +1,180 @@
|
|
|
1
|
-
//#region src/
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
12
|
-
outDir
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
155
|
+
readonly kind: 'module';
|
|
156
|
+
readonly id: string;
|
|
157
|
+
readonly api?: string;
|
|
158
|
+
readonly impl?: string;
|
|
159
|
+
readonly dependencies: readonly ArchicatDependency[];
|
|
28
160
|
}>;
|
|
29
|
-
|
|
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
|
|
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 };
|
package/dist/src/index.d.mts
CHANGED
|
@@ -1,32 +1,180 @@
|
|
|
1
|
-
//#region src/
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
12
|
-
outDir
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
155
|
+
readonly kind: 'module';
|
|
156
|
+
readonly id: string;
|
|
157
|
+
readonly api?: string;
|
|
158
|
+
readonly impl?: string;
|
|
159
|
+
readonly dependencies: readonly ArchicatDependency[];
|
|
28
160
|
}>;
|
|
29
|
-
|
|
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
|
|
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 };
|
package/dist/src/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(e){return Object.freeze({root:e.root
|
|
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
|
+
"version": "0.0.5",
|
|
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": "
|
|
59
|
+
"gitHead": "c17dd7ebf6530c88038a22113d7c6739a22550a9"
|
|
60
60
|
}
|