archicat 0.0.7 → 0.0.9
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 +5 -4
- package/dist/cli/index.mjs +18 -17
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -12,10 +12,11 @@ npm i -D archicat
|
|
|
12
12
|
|
|
13
13
|
## Why
|
|
14
14
|
|
|
15
|
-
TypeScript asks:
|
|
16
|
-
|
|
15
|
+
TypeScript asks: will this import resolve?
|
|
17
16
|
Archicat asks: should this import exist?
|
|
18
17
|
|
|
18
|
+
One is a compiler. The other is an architect.
|
|
19
|
+
|
|
19
20
|
## Definitions
|
|
20
21
|
|
|
21
22
|
### Module
|
|
@@ -183,8 +184,8 @@ App `tsconfig.json`:
|
|
|
183
184
|
## Commands
|
|
184
185
|
|
|
185
186
|
```bash
|
|
186
|
-
archicat
|
|
187
|
-
archicat
|
|
187
|
+
archicat build
|
|
188
|
+
archicat validate
|
|
188
189
|
archicat graph
|
|
189
190
|
archicat doctor
|
|
190
191
|
```
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import t from"node:path";import
|
|
2
|
-
`);if(e.file&&e.start!==void 0){let n=e.file.getLineAndCharacterOfPosition(e.start);return`${e.file.fileName}:${n.line+1}:${n.character+1} - ${t}`}return t}async function te(e=a.configFileName){let r=process.cwd(),i=t.resolve(r,e);if(!n.existsSync(i))throw Error(`Archicat config was not found: ${i}`);let o=await ne(i,r);oe(o,i);let s=re(o),c=t.resolve(r,s.root),l=t.resolve(c,s.outDir),u=t.resolve(l,a.generated.reportsDirName),d=ae(c,s.typescript.tsConfig.extends);return{configFilePath:i,rootDir:c,outDir:l,reportsDir:u,...d?{tsconfigPath:d}:{},config:o,resolvedConfig:s}}async function ne(e,t){return await r(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function re(e){return{root:e.root??a.root,outDir:e.outDir??a.outDir,typescript:ie(e),alias:{...a.alias,...e.alias??{}},prefixes:{module:e.prefixes?.module??a.prefixes.module,library:e.prefixes?.library??a.prefixes.library},modules:m(e.modules,a.modules),libraries:m(e.libraries,a.libraries),apps:m(e.apps,a.apps)}}function ie(e){let t=e.typescript?.tsConfig,n=a.typescript.tsConfig,r={include:[...t?.include??n.include],exclude:[...t?.exclude??n.exclude],files:[...t?.files??n.files]};return t?.extends&&(r.extends=t.extends),{tsConfig:r}}function m(e,t){return{include:[...e?.include??t.include]}}function ae(e,t){if(t)return l(e,t)}function oe(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat config: ${t}`);let n=e;h(n.root,`root`,t),h(n.outDir,`outDir`,t),se(n.typescript?.tsConfig,t),g(n.modules?.include,`modules.include`,t),g(n.libraries?.include,`libraries.include`,t),g(n.apps?.include,`apps.include`,t),le(n.alias,`alias`,t),_(n.prefixes?.module,`prefixes.module`,t),_(n.prefixes?.library,`prefixes.library`,t)}function se(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config typescript.tsConfig must be an object: ${t}`);let n=e;h(n.extends,`typescript.tsConfig.extends`,t),g(n.include,`typescript.tsConfig.include`,t),g(n.exclude,`typescript.tsConfig.exclude`,t),g(n.files,`typescript.tsConfig.files`,t),ce(n.compilerOptions,t)}function ce(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config typescript.tsConfig.compilerOptions must be an object: ${t}`);let n=e;if(Object.hasOwn(n,`paths`))throw Error(`Archicat config typescript.tsConfig.compilerOptions.paths is not supported. Move aliases into archicat.config.ts alias.`);if(Object.hasOwn(n,`baseUrl`))throw Error(`Archicat config typescript.tsConfig.compilerOptions.baseUrl is not supported. Move aliases into archicat.config.ts alias.`);if(Object.keys(n).length>0)throw Error(`Archicat config typescript.tsConfig.compilerOptions is not supported. Put compiler options in the base or app tsconfig.`)}function h(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function g(e,t,n){if(e!==void 0&&(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``)))throw Error(`Archicat config ${t} must be an array of non-empty strings: ${n}`)}function _(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``||e.includes(`*`)||e.endsWith(`/`)))throw Error(`Archicat config ${t} must be a non-empty prefix without wildcard or trailing slash: ${n}`)}function le(e,t,n){if(e!==void 0){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config ${t} must be an object of non-empty string aliases: ${n}`);for(let[r,i]of Object.entries(e))if(r.trim()===``||typeof i!=`string`||i.trim()===``)throw Error(`Archicat config ${t} must contain non-empty string aliases: ${n}`)}}function v(e,t,n){let r=t.flatMap(t=>ue(e,t,n));return Array.from(new Set(r)).sort((e,t)=>e.localeCompare(t))}function ue(e,r,i){let a=t.resolve(e,r);if(r.includes(`*`))return de(e,r).filter(e=>t.basename(e)===i);if(!n.existsSync(a))return[];let o=n.statSync(a);return o.isFile()?t.basename(a)===i?[a]:[]:o.isDirectory()?y(a,i):[]}function y(e,r){let i=[],a=n.readdirSync(e,{withFileTypes:!0});for(let n of a){if(pe(n.name))continue;let a=t.join(e,n.name);if(n.isDirectory()){i.push(...y(a,r));continue}n.isFile()&&n.name===r&&i.push(a)}return i}function de(e,r){let i=t.resolve(e,r).split(t.sep);if(i.filter(e=>e.includes(`*`)).length!==1)throw Error(`Archicat supports exactly one wildcard segment per include pattern: ${r}`);let a=i.findIndex(e=>e.includes(`*`)),o=i.slice(0,a).join(t.sep)||t.sep,s=i[a]??`*`,c=i.slice(a+1),l=fe(s);return n.existsSync(o)?n.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).filter(e=>l.test(e.name)).map(e=>t.join(o,e.name,...c)).filter(e=>n.existsSync(e)&&n.statSync(e).isFile()):[]}function fe(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function pe(e){return a.generated.ignoredDirectoryNames.includes(e)}async function b(e,t){switch(t){case`module`:return me(e);case`library`:return he(e);case`app`:return ge(e)}}async function me(e){let n=await x(e,t.dirname(e));return S(n,e,`module`),{kind:`module`,contractFilePath:e,definitionDir:t.dirname(e),contract:n}}async function he(e){let n=await x(e,t.dirname(e));return S(n,e,`library`),{kind:`library`,contractFilePath:e,definitionDir:t.dirname(e),contract:n}}async function ge(e){let n=await x(e,t.dirname(e));return S(n,e,`app`),{kind:`app`,contractFilePath:e,definitionDir:t.dirname(e),contract:n}}async function x(e,t){return await r(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function S(e,t,n){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat ${n} definition: ${t}`);let r=e;if(r.kind!==n)throw Error(`Archicat ${n} file must export define${ve(n)}(...): ${t}`);if(typeof r.name!=`string`||r.name.trim()===``)throw Error(`Archicat ${n} must define a non-empty name: ${t}`);if(n===`app`){_e(r.root,`root`,t),w(r.dependencies,t,n);return}let i=r;C(i.api,`api`,t,n),C(i.impl,`impl`,t,n)}function C(e,t,n,r){if(typeof e!=`object`||!e)throw Error(`Archicat ${r}.${t} must be a surface object: ${n}`);_e(e.root,`${t}.root`,n),w(e.dependencies,n,`${r}.${t}`)}function w(e,t,n){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${n} dependencies must be an array of non-empty strings: ${t}`)}function _e(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function ve(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function ye(e){let t=new Map;for(let n of e){let e=t.get(n.from)??[];e.push(n.to),t.set(n.from,e)}let n=new Set,r=new Set;for(let e of t.keys())T(e,t,n,r,[])}function T(e,t,n,r,i){if(!r.has(e)){if(n.has(e)){let t=i.indexOf(e),n=[...i.slice(t<0?0:t),e];throw Error(`Cyclic Archicat dependency detected: ${n.join(` -> `)}`)}n.add(e);for(let a of t.get(e)??[])T(a,t,n,r,[...i,e]);n.delete(e),r.add(e)}}function be(e){let t=/^(module|library)\.([a-z][a-z0-9-]*)\.(api|impl)$/u.exec(e);if(t)return{kind:t[1],name:t[2],surface:t[3]}}function xe(e){return`${e.kind}.${e.surface}`}function E(e,t,n){let r=be(t);if(!r)throw Error(`${D(e)} declares invalid dependency target "${t}".`);if(!n.has(t))throw Error(`${D(e)} declares unknown dependency "${t}".`);if(e.kind===r.kind&&e.name===r.name)throw Error(`${D(e)} cannot depend on itself: ${t}`);if(!Se(e,r))throw Error(`${D(e)} cannot depend on ${xe(r)} target "${t}".`)}function Se(e,t){switch(e.surface){case`api`:return e.kind===`module`?t.surface===`api`&&(t.kind===`module`||t.kind===`library`):e.kind===`library`?t.surface===`api`&&t.kind===`library`:!1;case`impl`:return e.kind===`module`?t.surface===`api`&&(t.kind===`module`||t.kind===`library`):e.kind===`library`?t.surface===`api`&&t.kind===`library`:!1;case`app`:return t.kind===`module`||t.kind===`library`}}function D(e){return e.kind===`app`?`App "${e.name}"`:`${Ce(e.kind)} "${e.name}" ${e.surface}`}function Ce(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function we(e,t){let n=t.filter(e=>e.kind===`module`).map(t=>Te(e,t)),r=t.filter(e=>e.kind===`library`).map(t=>Ee(e,t)),i=t.filter(e=>e.kind===`app`).map(e=>De(e)),a=[...n,...r];ke([...a,...i]);let o=Oe(a,i);return Ae(a,i,o.targets),ye(o.dependencies),{rootDir:e.rootDir,outDir:e.outDir,reportsDir:e.reportsDir,...e.tsconfigPath?{tsconfigPath:e.tsconfigPath}:{},configFilePath:e.configFilePath,config:e.resolvedConfig,modules:n,libraries:r,apps:i,definitions:a,graph:o}}function Te(e,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;A(r.name,i,`module`);let o=r.api.root?k(a,r.api.root,`api`,r.name):void 0,s=r.impl.root?k(a,r.impl.root,`impl`,r.name):void 0,c=`${e.resolvedConfig.prefixes.module}/${r.name}`;return{kind:`module`,name:r.name,apiTarget:`module.${r.name}.api`,implTarget:`module.${r.name}.impl`,alias:c,aliasGlob:`${c}/*`,implAlias:`${c}/impl`,implAliasGlob:`${c}/impl/*`,contractFilePath:i,definitionDir:a,api:O(o,r.api.dependencies,t.join(e.outDir,`modules`,r.name,`api`)),impl:O(s,r.impl.dependencies,t.join(e.outDir,`modules`,r.name,`impl`))}}function Ee(e,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;A(r.name,i,`library`);let o=r.api.root?k(a,r.api.root,`api`,r.name):void 0,s=r.impl.root?k(a,r.impl.root,`impl`,r.name):void 0,c=`${e.resolvedConfig.prefixes.library}/${r.name}`;return{kind:`library`,name:r.name,apiTarget:`library.${r.name}.api`,implTarget:`library.${r.name}.impl`,alias:c,aliasGlob:`${c}/*`,implAlias:`${c}/impl`,implAliasGlob:`${c}/impl/*`,contractFilePath:i,definitionDir:a,api:O(o,r.api.dependencies,t.join(e.outDir,`libraries`,r.name,`api`)),impl:O(s,r.impl.dependencies,t.join(e.outDir,`libraries`,r.name,`impl`))}}function De(e){let{contract:t,contractFilePath:n,definitionDir:r}=e;return A(t.name,n,`app`),{kind:`app`,name:t.name,target:`app.${t.name}`,contractFilePath:n,definitionDir:r,rootPath:t.root?k(r,t.root,`app`,t.name):r,dependencies:[...t.dependencies]}}function O(e,t,n){return{...e?{rootPath:e}:{},mirrorRootPath:n,dependencies:[...t]}}function k(e,r,i,a){let o=t.resolve(e,r);if(!n.existsSync(o))throw Error(`Definition "${a}" declares ${i} root that does not exist: ${o}`);if(!n.statSync(o).isDirectory())throw Error(`Definition "${a}" declares ${i} root that is not a directory: ${o}`);return o}function Oe(e,t){let n=e.flatMap(e=>[{key:e.apiTarget,kind:e.kind,name:e.name,surface:`api`},{key:e.implTarget,kind:e.kind,name:e.name,surface:`impl`}]),r=[...e.flatMap(e=>[...e.api.dependencies.map(t=>({from:e.apiTarget,to:t,origin:`declared`})),...e.impl.dependencies.map(t=>({from:e.implTarget,to:t,origin:`declared`}))]),...t.flatMap(e=>e.dependencies.map(t=>({from:e.target,to:t,origin:`declared`})))];return{targets:n,dependencies:[...e.map(e=>({from:e.implTarget,to:e.apiTarget,origin:`derived`})),...r]}}function A(e,t,n){if(!/^[a-z][a-z0-9-]*$/u.test(e))throw Error(`Invalid Archicat ${n} name "${e}" in ${t}. Use ^[a-z][a-z0-9-]*$`)}function ke(e){let t=new Map;for(let n of e){let e=`${n.kind}.${n.name}`,r=t.get(e);if(r)throw Error(`Duplicate Archicat ${n.kind} name "${n.name}" in ${r} and ${n.contractFilePath}`);t.set(e,n.contractFilePath)}}function Ae(e,t,n){let r=new Set(n.map(e=>e.key));for(let t of e){for(let e of t.api.dependencies)E(je(t,`api`),e,r);for(let e of t.impl.dependencies)E(je(t,`impl`),e,r)}for(let e of t)for(let t of e.dependencies)E({kind:`app`,name:e.name,surface:`app`,target:e.target},t,r)}function je(e,t){return{kind:e.kind,name:e.name,surface:t,target:t===`api`?e.apiTarget:e.implTarget}}async function j(e){let t=await te(e),n=v(t.rootDir,t.resolvedConfig.modules.include,`archicat.module.ts`),r=v(t.rootDir,t.resolvedConfig.libraries.include,`archicat.library.ts`),i=v(t.rootDir,t.resolvedConfig.apps.include,`archicat.app.ts`);if(n.length===0&&r.length===0&&i.length===0)throw Error(`No Archicat definition files matched configured include roots.`);return we(t,[...await Promise.all(n.map(e=>b(e,`module`))),...await Promise.all(r.map(e=>b(e,`library`))),...await Promise.all(i.map(e=>b(e,`app`)))])}function M(e){return e.split(t.sep).join(`/`)}function Me(e,n){let r=t.dirname(e),i=t.parse(n),a=t.join(i.dir,i.name),o=M(t.relative(r,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function N(e,n){let r=t.relative(n,e);return r===``||!!r&&!r.startsWith(`..`)&&!t.isAbsolute(r)}function P(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function F(e,n){return M(t.relative(e,n))}function I(e){return n.existsSync(e)?n.statSync(e).isFile()?Ne(e)?[e]:[]:Pe(e).filter(Ne).sort((e,t)=>e.localeCompare(t)):[]}function Ne(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function Pe(e){let r=[],i=n.readdirSync(e,{withFileTypes:!0});for(let n of i){let i=t.join(e,n.name);if(n.isDirectory()){r.push(...Pe(i));continue}n.isFile()&&r.push(i)}return r}function Fe(e){let t=i.createSourceFile(e,n.readFileSync(e,`utf8`),i.ScriptTarget.Latest,!0),r=[],a=e=>{if(i.isImportDeclaration(e)&&i.isStringLiteral(e.moduleSpecifier)&&r.push({moduleSpecifier:e.moduleSpecifier.text,kind:`import`}),i.isExportDeclaration(e)&&e.moduleSpecifier&&i.isStringLiteral(e.moduleSpecifier)&&r.push({moduleSpecifier:e.moduleSpecifier.text,kind:`export`}),i.isCallExpression(e)&&e.expression.kind===i.SyntaxKind.ImportKeyword){let[t]=e.arguments;t&&i.isStringLiteral(t)&&r.push({moduleSpecifier:t.text,kind:`dynamic-import`})}i.forEachChild(e,a)};return a(t),r}function Ie(e){let t=i.createSourceFile(e,n.readFileSync(e,`utf8`),i.ScriptTarget.Latest,!0),r=!1,a=e=>{if(!r){if(i.isExportAssignment(e)&&!e.isExportEquals){r=!0;return}if(Le(e)){r=!0;return}if(i.isExportDeclaration(e)&&e.exportClause&&i.isNamedExports(e.exportClause))for(let t of e.exportClause.elements){let e=t.name.text,n=t.propertyName?.text;if(e==="default"||n==="default"){r=!0;return}}i.forEachChild(e,a)}};return a(t),r}function Le(e){let t=i.canHaveModifiers(e)?i.getModifiers(e):void 0;if(!t)return!1;let n=t.some(e=>e.kind===i.SyntaxKind.ExportKeyword),r=t.some(e=>e.kind===i.SyntaxKind.DefaultKeyword);return n&&r}async function Re(e){return ze(await j(e))}function ze(e){let t=[],n=[...e.definitions.flatMap(e=>Be(e)),...e.apps.flatMap(e=>I(e.rootPath))];for(let r of n){let n=Ue(e,r);if(n)for(let i of Fe(r)){let a=Ve(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function Be(e){return[...e.api.rootPath?I(e.api.rootPath):[],...e.impl.rootPath?I(e.impl.rootPath):[]]}function Ve(e,t,n,r){let i=Ke(e,r);if(i)return qe(t,i)?void 0:i.surface===`impl`&&t.kind!==`app`?L(e,n,r,`${R(t)} cannot import implementation target "${i.target}". Implementation imports are allowed only from app composition roots.`):Je(e,t.target,i.target)?void 0:L(e,n,r,`${R(t)} imports "${i.target}" but does not declare a dependency that allows it.`);if(r.startsWith(`.`)||r.startsWith(`/`))return He(e,t,n,r)}function He(e,t,n,r){let i=Ue(e,We(n,r));if(!(!i||Ge(t,i)))return L(e,n,r,`${R(t)} imports ${R(i)} through a source path. Use an Archicat alias instead.`)}function Ue(e,t){let n=P(t);for(let t of e.definitions){if(t.api.rootPath&&N(n,P(t.api.rootPath)))return{kind:t.kind,name:t.name,surface:`api`,target:t.apiTarget,definition:t};if(t.impl.rootPath&&N(n,P(t.impl.rootPath)))return{kind:t.kind,name:t.name,surface:`impl`,target:t.implTarget,definition:t}}for(let t of e.apps)if(N(n,P(t.rootPath)))return{kind:`app`,name:t.name,surface:`app`,target:t.target,app:t}}function We(e,n){return P(n.startsWith(`/`)?n:t.resolve(t.dirname(e),n))}function Ge(e,t){return e.kind===t.kind&&e.name===t.name}function Ke(e,t){for(let n of e.definitions){if(n.implAlias&&(t===n.implAlias||t.startsWith(`${n.implAlias}/`)))return{kind:n.kind,name:n.name,surface:`impl`,target:n.implTarget};if(t===n.alias||t.startsWith(`${n.alias}/`))return{kind:n.kind,name:n.name,surface:`api`,target:n.apiTarget}}}function qe(e,t){return e.kind===t.kind&&e.name===t.name&&t.surface===`api`}function Je(e,t,n){let r=new Set,i=[t];for(;i.length>0;){let t=i.shift();if(t===n)return!0;if(!r.has(t)){r.add(t);for(let n of e.graph.dependencies.filter(e=>e.from===t))i.push(n.to)}}return!1}function L(e,t,n,r){return{filePath:F(e.rootDir,t),importPath:n,message:r}}function R(e){return e.kind===`app`?`App "${e.name}"`:`${Ye(e.kind)} "${e.name}" ${e.surface}`}function Ye(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function z(e){return{exitCode:0,lines:e.map(e=>({kind:`success`,message:e}))}}function Xe(e){return{exitCode:1,lines:e.map(e=>({kind:`error`,message:e}))}}async function Ze(e){let t=await Re(e.config);return t.length===0?z([`Architecture check passed.`]):Xe(t.map(e=>`${e.filePath}\n import: ${e.importPath}\n ${e.message}`))}async function Qe(e){let t=await j(e);return[...$e(t),...et(t),...ct(t)]}function $e(e){let t=B(e);return n.existsSync(t)?[]:[{severity:`warning`,message:`Generated tsconfig does not exist yet: ${t}. Run archicat generate.`}]}function et(e){let t=lt(e);if(!n.existsSync(t))return[{severity:`warning`,message:`Consumer tsconfig was not found: ${t}`}];let r=[],i=tt(t,r);if(!i)return r;let a=nt(i,t,r);return a?(rt(r,e,i),it(r,a),at(r,a),ot(r,a),st(r,i),r):r}function tt(e,t){try{return o(e)}catch(e){t.push({severity:`warning`,message:`Failed to parse consumer tsconfig: ${V(e)}`});return}}function nt(e,t,n){try{return s(e,t)}catch(e){n.push({severity:`warning`,message:V(e)});return}}function rt(e,t,n){let r=ut(t);n.extends!==r&&e.push({severity:`warning`,message:`Consumer tsconfig should extend ${r} for generated Archicat aliases to work.`})}function it(e,t){let n=t.rootDir;n!==`src`&&n!==`./src`||e.push({severity:`warning`,message:`compilerOptions.rootDir is set to src. Generated .archicat files live outside src and may break tsc.`})}function at(e,t){Object.hasOwn(t,`paths`)&&e.push({severity:`warning`,message:`compilerOptions.paths should move to archicat.config.ts alias. Consumer tsconfig paths can override generated Archicat aliases.`})}function ot(e,t){Object.hasOwn(t,`baseUrl`)&&e.push({severity:`warning`,message:`compilerOptions.baseUrl is not supported. Move aliases into archicat.config.ts alias.`})}function st(e,t){t.include===void 0&&t.exclude===void 0&&t.files===void 0||e.push({severity:`warning`,message:`Consumer tsconfig include/exclude/files should move to archicat.config.ts typescript.tsConfig so generated Archicat types stay included.`})}function ct(e){let r=[];for(let i of e.definitions){let e=t.join(i.definitionDir,`api`),a=t.join(i.definitionDir,`impl`);!i.api.rootPath&&n.existsSync(e)&&r.push({severity:`warning`,message:`${H(i.kind)} "${i.name}" has a physical api directory but its contract omits api.root. Archicat treats the public API as empty.`}),!i.impl.rootPath&&n.existsSync(a)&&r.push({severity:`warning`,message:`${H(i.kind)} "${i.name}" has a physical impl directory but its contract omits impl.root. Archicat treats the implementation as no-op.`})}return r}function lt(e){return t.join(e.rootDir,a.typescript.consumerTsconfigFileName)}function B(e){return t.join(e.outDir,a.generated.tsconfigFileName)}function ut(e){let n=M(t.relative(e.rootDir,B(e)));return dt(n)||(n=`./${n}`),n}function dt(e){return e.startsWith(`./`)||e.startsWith(`../`)}function V(e){return e instanceof Error?e.message:String(e)}function H(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}async function ft(e){let t=await Qe(e.config);return t.length===0?z([`Doctor found no issues.`]):{exitCode:+!!t.some(e=>e.severity===`error`),lines:t.map(e=>({kind:e.severity===`error`?`error`:`warning`,message:e.message}))}}function pt(e){n.existsSync(e)&&n.rmSync(e,{recursive:!0,force:!0}),n.mkdirSync(e,{recursive:!0})}function U(e,r){n.mkdirSync(t.dirname(e),{recursive:!0}),n.writeFileSync(e,r,`utf8`)}function W(e,t){U(e,`${JSON.stringify(t,null,2)}\n`)}function mt(e){let n=[...e.modules.map(e=>e.apiTarget),...e.libraries.map(e=>e.apiTarget)],r=n,i=e.libraries.map(e=>e.apiTarget),a=i,o=e.graph.targets.map(e=>e.key),s=`import 'archicat';
|
|
1
|
+
import{createRequire as e}from"node:module";import{createConsola as t}from"consola";import{colors as n}from"consola/utils";import r from"node:path";import i from"node:fs";import{createJiti as a}from"jiti";import o from"typescript";var s=class{static color=n;static title(e,t,r=[]){ee({title:`${e} ${t}`.trim(),renderedTitle:`${n.cyan(n.bold(e))} ${n.dim(t)}`,rows:r,formatValue:n.green})}static panel(e,t,r){ee({title:r===void 0?e:`${e} ${r}`,renderedTitle:`${n.cyan(n.bold(e))}${r===void 0?``:` ${n.green(String(r))}`}`,rows:t,formatValue:n.green})}static step(e,t){return`${n.cyan(e.padEnd(u,` `))}${t}`}static duration(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2)}s`}static emptyLine(){c.log(``)}static log(e,...t){c.log(e,...t)}static info(e,...t){c.info(e,...t)}static success(e,...t){c.success(e,...t)}static warn(e,...t){c.warn(e,...t)}static error(e,...t){c.error(e,...t)}};const c=t({level:999,formatOptions:{colors:!0,date:!1}}),l=/\u001B\[[0-9;]*m/g,u=10;function ee(e){let t=ie(e.title,e.rows);c.log([te(e,t),...e.rows.map(n=>re(n,t,e.formatValue)),ne(t)].join(`
|
|
2
|
+
`))}function te(e,t){let r=Math.max(1,t-d(e.title)-5);return`${n.dim(`╭─`)} ${e.renderedTitle} ${n.dim(`─`.repeat(r))}${n.dim(`╮`)}`}function ne(e){return`${n.dim(`╰`)}${n.dim(`─`.repeat(e-2))}${n.dim(`╯`)}`}function re(e,t,r){let i=e.label.padEnd(14,` `),a=String(e.value),o=d(`${i}${a}`),s=Math.max(0,t-o-4);return`${n.dim(`│`)} ${n.blue(i)}${r(a)}${` `.repeat(s)} ${n.dim(`│`)}`}function ie(e,t){let n=d(e)+6,r=Math.max(0,...t.map(e=>14+d(String(e.value))+4));return Math.max(48,n,r)}function d(e){return e.replace(l,``).length}const f=Object.freeze({configFileName:`archicat.config.ts`,root:`.`,outDir:`.archicat`,alias:Object.freeze({}),generated:Object.freeze({reportsDirName:`reports`,buildReportFileName:`build.report.json`,graphReportFileName:`graph.report.json`,tsconfigFileName:`tsconfig.json`,typesInclude:`./types/**/*.d.ts`,ignoredDirectoryNames:Object.freeze([`node_modules`,`.git`,`.archicat`,`archicat-report`,`dist`,`build`,`coverage`])}),typescript:Object.freeze({consumerTsconfigFileName:`tsconfig.json`,tsConfig:Object.freeze({include:Object.freeze([]),exclude:Object.freeze([]),files:Object.freeze([])})}),prefixes:Object.freeze({module:`@module`,library:`@library`}),modules:Object.freeze({include:Object.freeze([`./src/modules`])}),libraries:Object.freeze({include:Object.freeze([])}),apps:Object.freeze({include:Object.freeze([])})});function p(e){let t=i.readFileSync(e,`utf8`),n=o.parseConfigFileTextToJson(e,t);if(n.error)throw Error(ce(n.error));if(n.config==null||typeof n.config!=`object`||Array.isArray(n.config))throw Error(`Invalid tsconfig object: ${e}`);return n.config}function m(e,t=`tsconfig`){let n=e.compilerOptions;if(n==null)return{};if(typeof n!=`object`||Array.isArray(n))throw Error(`Tsconfig compilerOptions must be an object: ${t}`);return n}function ae(e,t){let n=e.extends;if(n===void 0)return[];if(typeof n==`string`)return[se(t,n)];if(Array.isArray(n)&&n.every(e=>typeof e==`string`))return n.map(e=>se(t,e));throw Error(`Tsconfig extends must be a string or string array: ${t}`)}function oe(t,n){return r.isAbsolute(n)||n.startsWith(`.`)?g(r.resolve(t,n),n):h(e(r.join(t,f.configFileName)),n,n)}function se(t,n){return r.isAbsolute(n)||n.startsWith(`.`)?g(r.resolve(r.dirname(t),n),t):h(e(t),n,t)}function h(e,t,n){for(let n of _(t))try{return e.resolve(n)}catch{continue}throw Error(`Unable to resolve tsconfig extends "${t}": ${n}`)}function g(e,t){for(let t of _(e))if(i.existsSync(t)&&i.statSync(t).isFile())return t;throw Error(`Unable to resolve tsconfig extends "${e}": ${t}`)}function _(e){return[e,`${e}.json`,r.join(e,f.typescript.consumerTsconfigFileName)]}function ce(e){let t=o.flattenDiagnosticMessageText(e.messageText,`
|
|
3
|
+
`);if(e.file&&e.start!==void 0){let n=e.file.getLineAndCharacterOfPosition(e.start);return`${e.file.fileName}:${n.line+1}:${n.character+1} - ${t}`}return t}async function le(e=f.configFileName){let t=process.cwd(),n=r.resolve(t,e);if(!i.existsSync(n))throw Error(`Archicat config was not found: ${n}`);let a=await ue(n,t);me(a,n);let o=de(a),s=r.resolve(t,o.root),c=r.resolve(s,o.outDir),l=r.resolve(c,f.generated.reportsDirName),u=pe(s,o.typescript.tsConfig.extends);return{configFilePath:n,rootDir:s,outDir:c,reportsDir:l,...u?{tsconfigPath:u}:{},config:a,resolvedConfig:o}}async function ue(e,t){return await a(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function de(e){return{root:e.root??f.root,outDir:e.outDir??f.outDir,typescript:fe(e),alias:{...f.alias,...e.alias??{}},prefixes:{module:e.prefixes?.module??f.prefixes.module,library:e.prefixes?.library??f.prefixes.library},modules:v(e.modules,f.modules),libraries:v(e.libraries,f.libraries),apps:v(e.apps,f.apps)}}function fe(e){let t=e.typescript?.tsConfig,n=f.typescript.tsConfig,r={include:[...t?.include??n.include],exclude:[...t?.exclude??n.exclude],files:[...t?.files??n.files]};return t?.extends&&(r.extends=t.extends),{tsConfig:r}}function v(e,t){return{include:[...e?.include??t.include]}}function pe(e,t){if(t)return oe(e,t)}function me(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat config: ${t}`);let n=e;y(n.root,`root`,t),y(n.outDir,`outDir`,t),he(n.typescript?.tsConfig,t),b(n.modules?.include,`modules.include`,t),b(n.libraries?.include,`libraries.include`,t),b(n.apps?.include,`apps.include`,t),ve(n.alias,`alias`,t),_e(n.prefixes?.module,`prefixes.module`,t),_e(n.prefixes?.library,`prefixes.library`,t)}function he(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config typescript.tsConfig must be an object: ${t}`);let n=e;y(n.extends,`typescript.tsConfig.extends`,t),b(n.include,`typescript.tsConfig.include`,t),b(n.exclude,`typescript.tsConfig.exclude`,t),b(n.files,`typescript.tsConfig.files`,t),ge(n.compilerOptions,t)}function ge(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config typescript.tsConfig.compilerOptions must be an object: ${t}`);let n=e;if(Object.hasOwn(n,`paths`))throw Error(`Archicat config typescript.tsConfig.compilerOptions.paths is not supported. Move aliases into archicat.config.ts alias.`);if(Object.hasOwn(n,`baseUrl`))throw Error(`Archicat config typescript.tsConfig.compilerOptions.baseUrl is not supported. Move aliases into archicat.config.ts alias.`);if(Object.keys(n).length>0)throw Error(`Archicat config typescript.tsConfig.compilerOptions is not supported. Put compiler options in the base or app tsconfig.`)}function 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 b(e,t,n){if(e!==void 0&&(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``)))throw Error(`Archicat config ${t} must be an array of non-empty strings: ${n}`)}function _e(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 ve(e,t,n){if(e!==void 0){if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Archicat config ${t} must be an object of non-empty string aliases: ${n}`);for(let[r,i]of Object.entries(e))if(r.trim()===``||typeof i!=`string`||i.trim()===``)throw Error(`Archicat config ${t} must contain non-empty string aliases: ${n}`)}}function x(e,t,n){let r=t.flatMap(t=>ye(e,t,n));return Array.from(new Set(r)).sort((e,t)=>e.localeCompare(t))}function ye(e,t,n){let a=r.resolve(e,t);if(t.includes(`*`))return xe(e,t).filter(e=>r.basename(e)===n);if(!i.existsSync(a))return[];let o=i.statSync(a);return o.isFile()?r.basename(a)===n?[a]:[]:o.isDirectory()?be(a,n):[]}function be(e,t){let n=[],a=i.readdirSync(e,{withFileTypes:!0});for(let i of a){if(Ce(i.name))continue;let a=r.join(e,i.name);if(i.isDirectory()){n.push(...be(a,t));continue}i.isFile()&&i.name===t&&n.push(a)}return n}function xe(e,t){let n=r.resolve(e,t).split(r.sep);if(n.filter(e=>e.includes(`*`)).length!==1)throw Error(`Archicat supports exactly one wildcard segment per include pattern: ${t}`);let a=n.findIndex(e=>e.includes(`*`)),o=n.slice(0,a).join(r.sep)||r.sep,s=n[a]??`*`,c=n.slice(a+1),l=Se(s);return i.existsSync(o)?i.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).filter(e=>l.test(e.name)).map(e=>r.join(o,e.name,...c)).filter(e=>i.existsSync(e)&&i.statSync(e).isFile()):[]}function Se(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function Ce(e){return f.generated.ignoredDirectoryNames.includes(e)}async function S(e,t){switch(t){case`module`:return we(e);case`library`:return Te(e);case`app`:return Ee(e)}}async function we(e){let t=await C(e,r.dirname(e));return w(t,e,`module`),{kind:`module`,contractFilePath:e,definitionDir:r.dirname(e),contract:t}}async function Te(e){let t=await C(e,r.dirname(e));return w(t,e,`library`),{kind:`library`,contractFilePath:e,definitionDir:r.dirname(e),contract:t}}async function Ee(e){let t=await C(e,r.dirname(e));return w(t,e,`app`),{kind:`app`,contractFilePath:e,definitionDir:r.dirname(e),contract:t}}async function C(e,t){return await a(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function w(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${ke(n)}(...): ${t}`);if(typeof r.name!=`string`||r.name.trim()===``)throw Error(`Archicat ${n} must define a non-empty name: ${t}`);if(n===`app`){Oe(r.root,`root`,t),De(r.dependencies,t,n);return}let i=r;T(i.api,`api`,t,n),T(i.impl,`impl`,t,n)}function T(e,t,n,r){if(typeof e!=`object`||!e)throw Error(`Archicat ${r}.${t} must be a surface object: ${n}`);Oe(e.root,`${t}.root`,n),De(e.dependencies,n,`${r}.${t}`)}function De(e,t,n){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${n} dependencies must be an array of non-empty strings: ${t}`)}function Oe(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 ke(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function Ae(e){let t=new Map;for(let n of e){let e=t.get(n.from)??[];e.push(n.to),t.set(n.from,e)}let n=new Set,r=new Set;for(let e of t.keys())E(e,t,n,r,[])}function E(e,t,n,r,i){if(!r.has(e)){if(n.has(e)){let t=i.indexOf(e),n=[...i.slice(t<0?0:t),e];throw Error(`Cyclic Archicat dependency detected: ${n.join(` -> `)}`)}n.add(e);for(let a of t.get(e)??[])E(a,t,n,r,[...i,e]);n.delete(e),r.add(e)}}function je(e){let t=/^(module|library)\.([a-z][a-z0-9-]*)\.(api|impl)$/u.exec(e);if(t)return{kind:t[1],name:t[2],surface:t[3]}}function Me(e){return`${e.kind}.${e.surface}`}function D(e,t,n){let r=je(t);if(!r)throw Error(`${O(e)} declares invalid dependency target "${t}".`);if(!n.has(t))throw Error(`${O(e)} declares unknown dependency "${t}".`);if(e.kind===r.kind&&e.name===r.name)throw Error(`${O(e)} cannot depend on itself: ${t}`);if(!Ne(e,r))throw Error(`${O(e)} cannot depend on ${Me(r)} target "${t}".`)}function Ne(e,t){switch(e.surface){case`api`:return e.kind===`module`?t.surface===`api`&&(t.kind===`module`||t.kind===`library`):e.kind===`library`?t.surface===`api`&&t.kind===`library`:!1;case`impl`:return e.kind===`module`?t.surface===`api`&&(t.kind===`module`||t.kind===`library`):e.kind===`library`?t.surface===`api`&&t.kind===`library`:!1;case`app`:return t.kind===`module`||t.kind===`library`}}function O(e){return e.kind===`app`?`App "${e.name}"`:`${Pe(e.kind)} "${e.name}" ${e.surface}`}function Pe(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function Fe(e,t){let n=t.filter(e=>e.kind===`module`).map(t=>Ie(e,t)),r=t.filter(e=>e.kind===`library`).map(t=>Le(e,t)),i=t.filter(e=>e.kind===`app`).map(e=>Re(e)),a=[...n,...r];Be([...a,...i]);let o=ze(a,i);return Ve(a,i,o.targets),Ae(o.dependencies),{rootDir:e.rootDir,outDir:e.outDir,reportsDir:e.reportsDir,...e.tsconfigPath?{tsconfigPath:e.tsconfigPath}:{},configFilePath:e.configFilePath,config:e.resolvedConfig,modules:n,libraries:r,apps:i,definitions:a,graph:o}}function Ie(e,t){let{contract:n,contractFilePath:i,definitionDir:a}=t;j(n.name,i,`module`);let o=n.api.root?A(a,n.api.root,`api`,n.name):void 0,s=n.impl.root?A(a,n.impl.root,`impl`,n.name):void 0,c=`${e.resolvedConfig.prefixes.module}/${n.name}`;return{kind:`module`,name:n.name,apiTarget:`module.${n.name}.api`,implTarget:`module.${n.name}.impl`,alias:c,aliasGlob:`${c}/*`,implAlias:`${c}/impl`,implAliasGlob:`${c}/impl/*`,contractFilePath:i,definitionDir:a,api:k(o,n.api.dependencies,r.join(e.outDir,`modules`,n.name,`api`)),impl:k(s,n.impl.dependencies,r.join(e.outDir,`modules`,n.name,`impl`))}}function Le(e,t){let{contract:n,contractFilePath:i,definitionDir:a}=t;j(n.name,i,`library`);let o=n.api.root?A(a,n.api.root,`api`,n.name):void 0,s=n.impl.root?A(a,n.impl.root,`impl`,n.name):void 0,c=`${e.resolvedConfig.prefixes.library}/${n.name}`;return{kind:`library`,name:n.name,apiTarget:`library.${n.name}.api`,implTarget:`library.${n.name}.impl`,alias:c,aliasGlob:`${c}/*`,implAlias:`${c}/impl`,implAliasGlob:`${c}/impl/*`,contractFilePath:i,definitionDir:a,api:k(o,n.api.dependencies,r.join(e.outDir,`libraries`,n.name,`api`)),impl:k(s,n.impl.dependencies,r.join(e.outDir,`libraries`,n.name,`impl`))}}function Re(e){let{contract:t,contractFilePath:n,definitionDir:r}=e;return j(t.name,n,`app`),{kind:`app`,name:t.name,target:`app.${t.name}`,contractFilePath:n,definitionDir:r,rootPath:t.root?A(r,t.root,`app`,t.name):r,dependencies:[...t.dependencies]}}function k(e,t,n){return{...e?{rootPath:e}:{},mirrorRootPath:n,dependencies:[...t]}}function A(e,t,n,a){let o=r.resolve(e,t);if(!i.existsSync(o))throw Error(`Definition "${a}" declares ${n} root that does not exist: ${o}`);if(!i.statSync(o).isDirectory())throw Error(`Definition "${a}" declares ${n} root that is not a directory: ${o}`);return o}function ze(e,t){let n=e.flatMap(e=>[{key:e.apiTarget,kind:e.kind,name:e.name,surface:`api`},{key:e.implTarget,kind:e.kind,name:e.name,surface:`impl`}]),r=[...e.flatMap(e=>[...e.api.dependencies.map(t=>({from:e.apiTarget,to:t,origin:`declared`})),...e.impl.dependencies.map(t=>({from:e.implTarget,to:t,origin:`declared`}))]),...t.flatMap(e=>e.dependencies.map(t=>({from:e.target,to:t,origin:`declared`})))];return{targets:n,dependencies:[...e.map(e=>({from:e.implTarget,to:e.apiTarget,origin:`derived`})),...r]}}function j(e,t,n){if(!/^[a-z][a-z0-9-]*$/u.test(e))throw Error(`Invalid Archicat ${n} name "${e}" in ${t}. Use ^[a-z][a-z0-9-]*$`)}function Be(e){let t=new Map;for(let n of e){let e=`${n.kind}.${n.name}`,r=t.get(e);if(r)throw Error(`Duplicate Archicat ${n.kind} name "${n.name}" in ${r} and ${n.contractFilePath}`);t.set(e,n.contractFilePath)}}function Ve(e,t,n){let r=new Set(n.map(e=>e.key));for(let t of e){for(let e of t.api.dependencies)D(He(t,`api`),e,r);for(let e of t.impl.dependencies)D(He(t,`impl`),e,r)}for(let e of t)for(let t of e.dependencies)D({kind:`app`,name:e.name,surface:`app`,target:e.target},t,r)}function He(e,t){return{kind:e.kind,name:e.name,surface:t,target:t===`api`?e.apiTarget:e.implTarget}}async function Ue(e){let t=await le(e),n=x(t.rootDir,t.resolvedConfig.modules.include,`archicat.module.ts`),r=x(t.rootDir,t.resolvedConfig.libraries.include,`archicat.library.ts`),i=x(t.rootDir,t.resolvedConfig.apps.include,`archicat.app.ts`);if(n.length===0&&r.length===0&&i.length===0)throw Error(`No Archicat definition files matched configured include roots.`);return Fe(t,[...await Promise.all(n.map(e=>S(e,`module`))),...await Promise.all(r.map(e=>S(e,`library`))),...await Promise.all(i.map(e=>S(e,`app`)))])}var We=class{options;project;constructor(e){this.options=e}async getProject(){return this.project??=await Ue(this.options.config),this.project}},M=class e{name;steps=[];constructor(e){this.name=e}static make(t){return new e(t)}use(e){return this.steps.push(e),this}async run(e){let t=Date.now(),n=new We(e),r=await n.getProject(),i={kind:`title`,product:`ArchiCat`,command:this.name,rows:[{label:`config`,value:Ge(r.configFilePath)},{label:`output`,value:Ge(r.outDir)}]},a=[],o=[];for(let e of this.steps){let r=await e.run(n);if(a.push(...r.lines.filter(e=>e.kind===`panel`)),o.push(...r.lines.filter(e=>e.kind!==`panel`)),r.exitCode!==0)return o.push({kind:`error`,label:`failed`,message:`Failed in ${s.duration(Date.now()-t)}`}),o.push({kind:`info`,message:``}),{exitCode:r.exitCode,lines:[i,...a,...o]}}return{exitCode:0,lines:[i,...a,...o,{kind:`success`,label:`done`,message:`Completed in ${s.duration(Date.now()-t)}`},{kind:`info`,message:``}]}}};function Ge(e){let t=r.relative(process.cwd(),e);return!t||t.startsWith(`..`)?e:t}function N(e){return e.split(r.sep).join(`/`)}function Ke(e,t){let n=r.dirname(e),i=r.parse(t),a=r.join(i.dir,i.name),o=N(r.relative(n,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function P(e,t){let n=r.relative(t,e);return n===``||!!n&&!n.startsWith(`..`)&&!r.isAbsolute(n)}function F(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function I(e,t){return N(r.relative(e,t))}function qe(e){return[...Je(e),...nt(e)]}function Je(e){let t=rt(e);if(!i.existsSync(t))return[{severity:`warning`,message:`Consumer tsconfig was not found: ${t}`}];let n=[],r=Ye(t,n);if(!r)return n;let a=Xe(r,t,n);return a?(Ze(n,e,r),Qe(n,a),$e(n,a),et(n,a),tt(n,r),n):n}function Ye(e,t){try{return p(e)}catch(e){t.push({severity:`warning`,message:`Failed to parse consumer tsconfig: ${L(e)}`});return}}function Xe(e,t,n){try{return m(e,t)}catch(e){n.push({severity:`warning`,message:L(e)});return}}function Ze(e,t,n){let r=at(t);n.extends!==r&&e.push({severity:`warning`,message:`Consumer tsconfig should extend ${r} for generated Archicat aliases to work.`})}function Qe(e,t){let n=t.rootDir;n!==`src`&&n!==`./src`||e.push({severity:`warning`,message:`compilerOptions.rootDir is set to src. Generated .archicat files live outside src and may break tsc.`})}function $e(e,t){Object.hasOwn(t,`paths`)&&e.push({severity:`warning`,message:`compilerOptions.paths should move to archicat.config.ts alias. Consumer tsconfig paths can override generated Archicat aliases.`})}function et(e,t){Object.hasOwn(t,`baseUrl`)&&e.push({severity:`warning`,message:`compilerOptions.baseUrl is not supported. Move aliases into archicat.config.ts alias.`})}function tt(e,t){t.include===void 0&&t.exclude===void 0&&t.files===void 0||e.push({severity:`warning`,message:`Consumer tsconfig include/exclude/files should move to archicat.config.ts typescript.tsConfig so generated Archicat types stay included.`})}function nt(e){let t=[];for(let n of e.definitions){let e=r.join(n.definitionDir,`api`),a=r.join(n.definitionDir,`impl`);!n.api.rootPath&&i.existsSync(e)&&t.push({severity:`warning`,message:`${R(n.kind)} "${n.name}" has a physical api directory but its contract omits api.root. Archicat treats the public API as empty.`}),!n.impl.rootPath&&i.existsSync(a)&&t.push({severity:`warning`,message:`${R(n.kind)} "${n.name}" has a physical impl directory but its contract omits impl.root. Archicat treats the implementation as no-op.`})}return t}function rt(e){return r.join(e.rootDir,f.typescript.consumerTsconfigFileName)}function it(e){return r.join(e.outDir,f.generated.tsconfigFileName)}function at(e){let t=N(r.relative(e.rootDir,it(e)));return ot(t)||(t=`./${t}`),t}function ot(e){return e.startsWith(`./`)||e.startsWith(`../`)}function L(e){return e instanceof Error?e.message:String(e)}function R(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function z(e){return i.existsSync(e)?i.statSync(e).isFile()?B(e)?[e]:[]:V(e).filter(B).sort((e,t)=>e.localeCompare(t)):[]}function B(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function V(e){let t=[],n=i.readdirSync(e,{withFileTypes:!0});for(let i of n){let n=r.join(e,i.name);if(i.isDirectory()){t.push(...V(n));continue}i.isFile()&&t.push(n)}return t}function st(e){let t=o.createSourceFile(e,i.readFileSync(e,`utf8`),o.ScriptTarget.Latest,!0),n=[],r=e=>{if(o.isImportDeclaration(e)&&o.isStringLiteral(e.moduleSpecifier)&&n.push({moduleSpecifier:e.moduleSpecifier.text,kind:`import`}),o.isExportDeclaration(e)&&e.moduleSpecifier&&o.isStringLiteral(e.moduleSpecifier)&&n.push({moduleSpecifier:e.moduleSpecifier.text,kind:`export`}),o.isCallExpression(e)&&e.expression.kind===o.SyntaxKind.ImportKeyword){let[t]=e.arguments;t&&o.isStringLiteral(t)&&n.push({moduleSpecifier:t.text,kind:`dynamic-import`})}o.forEachChild(e,r)};return r(t),n}function ct(e){let t=o.createSourceFile(e,i.readFileSync(e,`utf8`),o.ScriptTarget.Latest,!0),n=!1,r=e=>{if(!n){if(o.isExportAssignment(e)&&!e.isExportEquals){n=!0;return}if(lt(e)){n=!0;return}if(o.isExportDeclaration(e)&&e.exportClause&&o.isNamedExports(e.exportClause))for(let t of e.exportClause.elements){let e=t.name.text,r=t.propertyName?.text;if(e==="default"||r==="default"){n=!0;return}}o.forEachChild(e,r)}};return r(t),n}function lt(e){let t=o.canHaveModifiers(e)?o.getModifiers(e):void 0;if(!t)return!1;let n=t.some(e=>e.kind===o.SyntaxKind.ExportKeyword),r=t.some(e=>e.kind===o.SyntaxKind.DefaultKeyword);return n&&r}function ut(e){return ft(e)}function dt(e){return`${e.filePath}\n import: ${e.importPath}\n ${e.message}`}function ft(e){let t=[],n=[...e.definitions.flatMap(e=>pt(e)),...e.apps.flatMap(e=>z(e.rootPath))];for(let r of n){let n=H(e,r);if(n)for(let i of st(r)){let a=mt(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function pt(e){return[...e.api.rootPath?z(e.api.rootPath):[],...e.impl.rootPath?z(e.impl.rootPath):[]]}function mt(e,t,n,r){let i=vt(e,r);if(i)return yt(t,i)?void 0:i.surface===`impl`&&t.kind!==`app`?U(e,n,r,`${W(t)} cannot import implementation target "${i.target}". Implementation imports are allowed only from app composition roots.`):bt(e,t.target,i.target)?void 0:U(e,n,r,`${W(t)} imports "${i.target}" but does not declare a dependency that allows it.`);if(r.startsWith(`.`)||r.startsWith(`/`))return ht(e,t,n,r)}function ht(e,t,n,r){let i=H(e,gt(n,r));if(!(!i||_t(t,i)))return U(e,n,r,`${W(t)} imports ${W(i)} through a source path. Use an Archicat alias instead.`)}function H(e,t){let n=F(t);for(let t of e.definitions){if(t.api.rootPath&&P(n,F(t.api.rootPath)))return{kind:t.kind,name:t.name,surface:`api`,target:t.apiTarget,definition:t};if(t.impl.rootPath&&P(n,F(t.impl.rootPath)))return{kind:t.kind,name:t.name,surface:`impl`,target:t.implTarget,definition:t}}for(let t of e.apps)if(P(n,F(t.rootPath)))return{kind:`app`,name:t.name,surface:`app`,target:t.target,app:t}}function gt(e,t){return F(t.startsWith(`/`)?t:r.resolve(r.dirname(e),t))}function _t(e,t){return e.kind===t.kind&&e.name===t.name}function vt(e,t){for(let n of e.definitions){if(n.implAlias&&(t===n.implAlias||t.startsWith(`${n.implAlias}/`)))return{kind:n.kind,name:n.name,surface:`impl`,target:n.implTarget};if(t===n.alias||t.startsWith(`${n.alias}/`))return{kind:n.kind,name:n.name,surface:`api`,target:n.apiTarget}}}function yt(e,t){return e.kind===t.kind&&e.name===t.name&&t.surface===`api`}function bt(e,t,n){let r=new Set,i=[t];for(;i.length>0;){let t=i.shift();if(t===n)return!0;if(!r.has(t)){r.add(t);for(let n of e.graph.dependencies.filter(e=>e.from===t))i.push(n.to)}}return!1}function U(e,t,n,r){return{filePath:I(e.rootDir,t),importPath:n,message:r}}function W(e){return e.kind===`app`?`App "${e.name}"`:`${xt(e.kind)} "${e.name}" ${e.surface}`}function xt(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function St(e){i.existsSync(e)&&i.rmSync(e,{recursive:!0,force:!0}),i.mkdirSync(e,{recursive:!0})}function G(e,t){i.mkdirSync(r.dirname(e),{recursive:!0}),i.writeFileSync(e,t,`utf8`)}function K(e,t){G(e,`${JSON.stringify(t,null,2)}\n`)}function Ct(e){let t=[...e.modules.map(e=>e.apiTarget),...e.libraries.map(e=>e.apiTarget)],n=t,i=e.libraries.map(e=>e.apiTarget),a=i,o=e.graph.targets.map(e=>e.key),s=`import 'archicat';
|
|
3
4
|
|
|
4
5
|
declare module 'archicat' {
|
|
5
|
-
${
|
|
6
|
+
${q(`ArchicatModuleApiDependencies`,t)}
|
|
6
7
|
|
|
7
|
-
${
|
|
8
|
+
${q(`ArchicatModuleImplDependencies`,n)}
|
|
8
9
|
|
|
9
|
-
${
|
|
10
|
+
${q(`ArchicatLibraryApiDependencies`,i)}
|
|
10
11
|
|
|
11
|
-
${
|
|
12
|
+
${q(`ArchicatLibraryImplDependencies`,a)}
|
|
12
13
|
|
|
13
|
-
${
|
|
14
|
+
${q(`ArchicatAppDependencies`,o)}
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export {};
|
|
17
|
-
`;
|
|
18
|
-
`)}\n }`}function
|
|
19
|
-
`);return}let
|
|
20
|
-
`)}function
|
|
21
|
-
export const ${
|
|
18
|
+
`;G(r.join(e.outDir,`types`,`graph.d.ts`),s)}function q(e,t){return` interface ${e} {\n${Array.from(new Set(t)).sort((e,t)=>e.localeCompare(t)).map(e=>` '${e}': true;`).join(`
|
|
19
|
+
`)}\n }`}function wt(e){for(let t of e)switch(t.kind){case`module`:Tt(t);break;case`library`:Et(t);break}}function Tt(e){Dt(e.api),Ot(e,`module`)}function Et(e){Dt(e.api),Ot(e,`library`)}function Dt(e){if(!e.rootPath){G(r.join(e.mirrorRootPath,`index.ts`),`${J()}export {};
|
|
20
|
+
`);return}let t=z(e.rootPath),n=new Set;for(let i of t){let t=N(r.relative(e.rootPath,i));n.add(t),kt(r.join(e.mirrorRootPath,t),i)}n.has(`index.ts`)||G(r.join(e.mirrorRootPath,`index.ts`),`${J()}export {};
|
|
21
|
+
`)}function Ot(e,t){let n=e.impl.rootPath?At(e.impl.rootPath):void 0;if(!n){let n=t===`module`?`ArchicatModuleImplementation`:`ArchicatLibraryImplementation`,i=`${J()}
|
|
22
|
+
export const ${n} = {
|
|
22
23
|
name: '${e.name}',
|
|
23
24
|
assemblies: [],
|
|
24
25
|
schemas: [],
|
|
25
26
|
routes: [],
|
|
26
27
|
} as const;
|
|
27
28
|
|
|
28
|
-
export default ${
|
|
29
|
-
`;
|
|
29
|
+
export default ${n};
|
|
30
|
+
`;G(r.join(e.impl.mirrorRootPath,`index.ts`),i);return}kt(r.join(e.impl.mirrorRootPath,`index.ts`),n)}function kt(e,t){let n=Ke(e,t),r=ct(t)?`export { default } from '${n}';\n`:``;G(e,`${J()}
|
|
30
31
|
export * from '${n}';
|
|
31
|
-
${r}`)}function
|
|
32
|
-
`}function
|
|
33
|
-
`))}function
|
|
32
|
+
${r}`)}function At(e){for(let t of[`index.ts`,`index.mts`,`index.cts`,`index.tsx`]){let n=r.join(e,t);if(z(n).length>0)return n}}function J(){return`// Mirrored by Archicat.
|
|
33
|
+
`}function jt(e){K(r.join(e.reportsDir,f.generated.buildReportFileName),Mt(e)),K(r.join(e.reportsDir,f.generated.graphReportFileName),Nt(e))}function Mt(e){return{generatedBy:`archicat`,schemaVersion:1,prefixes:e.config.prefixes,outputs:{outDir:I(e.rootDir,e.outDir),reportsDir:I(e.rootDir,e.reportsDir)},targets:e.graph.targets.map(e=>e.key),definitions:[...e.definitions.map(t=>Pt(e,t)),...e.apps.map(t=>({kind:t.kind,name:t.name,targets:{app:t.target},aliases:{},dependencies:t.dependencies,contractFilePath:I(e.rootDir,t.contractFilePath),source:{root:I(e.rootDir,t.rootPath)},mirror:{}}))],dependencies:e.graph.dependencies}}function Nt(e){return{generatedBy:`archicat`,schemaVersion:1,targets:e.graph.targets.map(e=>e.key),dependencies:e.graph.dependencies}}function Pt(e,t){return{kind:t.kind,name:t.name,targets:{api:t.apiTarget,impl:t.implTarget},aliases:{api:t.alias,impl:e.apps.length>0?t.implAlias:void 0},dependencies:{api:t.api.dependencies,impl:t.impl.dependencies},contractFilePath:I(e.rootDir,t.contractFilePath),source:{root:I(e.rootDir,t.definitionDir),api:t.api.rootPath?I(e.rootDir,t.api.rootPath):void 0,impl:t.impl.rootPath?I(e.rootDir,t.impl.rootPath):void 0},mirror:{api:I(e.rootDir,t.api.mirrorRootPath),impl:I(e.rootDir,t.impl.mirrorRootPath)}}}function Ft(e){Gt(e.tsconfigPath),K(r.join(e.outDir,f.generated.tsconfigFileName),It(e))}function It(e){let t={compilerOptions:Lt(e),include:zt(e)},n=Rt(e),r=Bt(e),i=Vt(e);return n&&(t.extends=n),r.length>0&&(t.exclude=r),i.length>0&&(t.files=i),t}function Lt(e){let t=Ut(e),n=Ht(e);return Jt(e,t,n),{paths:{...t,...n}}}function Rt(e){return e.tsconfigPath?X(e.outDir,e.tsconfigPath):void 0}function zt(e){return Wt([...Y(e,e.config.typescript.tsConfig.include),f.generated.typesInclude])}function Bt(e){return Y(e,e.config.typescript.tsConfig.exclude)}function Vt(e){return Y(e,e.config.typescript.tsConfig.files)}function Ht(e){let t={},n=e.apps.length>0;for(let i of e.definitions)t[i.alias]=[X(e.outDir,r.join(i.api.mirrorRootPath,`index.ts`))],t[i.aliasGlob]=[X(e.outDir,r.join(i.api.mirrorRootPath,`*`))],n&&i.implAlias&&i.implAliasGlob&&(t[i.implAlias]=[X(e.outDir,r.join(i.impl.mirrorRootPath,`index.ts`))],t[i.implAliasGlob]=[X(e.outDir,r.join(i.impl.mirrorRootPath,`*`))]);return t}function Ut(e){let t={};for(let[n,i]of Object.entries(e.config.alias)){let a=r.isAbsolute(i)?i:r.resolve(e.rootDir,i);t[n]=[X(e.outDir,a)]}return t}function Y(e,t){return t.map(t=>{let n=r.isAbsolute(t)?t:r.resolve(e.rootDir,t);return X(e.outDir,n)})}function X(e,t){let n=N(r.relative(e,t));return n.startsWith(`.`)||(n=`./${n}`),n}function Wt(e){return[...new Set(e)]}function Gt(e){e&&Z(e,new Set,new Set)}function Z(e,t,n){let i=r.resolve(e);if(n.has(i))return;if(t.has(i))throw Error(`Circular tsconfig extends chain detected: ${i}`);t.add(i);let a=p(i),o=m(a,i);Kt(o,i),qt(o,i);for(let e of ae(a,i))Z(e,t,n);t.delete(i),n.add(i)}function Kt(e,t){if(Object.hasOwn(e,`paths`))throw Error(`Base tsconfig compilerOptions.paths is not supported by Archicat. Move aliases into archicat.config.ts alias: ${t}`)}function qt(e,t){if(Object.hasOwn(e,`baseUrl`))throw Error(`Base tsconfig compilerOptions.baseUrl is not supported by Archicat. Move aliases into archicat.config.ts alias: ${t}`)}function Jt(e,t,n){let r=Object.keys(t),i=Object.keys(n),a=Object.values(e.config.prefixes);for(let e of r){if(i.includes(e))throw Error(`Alias conflict: archicat.config.ts alias already defines "${e}", but Archicat needs it.`);for(let t of a)if(e===t||e===`${t}/*`||e.startsWith(`${t}/`))throw Error(`Alias conflict: archicat.config.ts alias "${e}" is inside Archicat reserved prefix "${t}". Remove the alias or configure another Archicat prefix.`)}}function Yt(e){Xt(e),St(e.outDir),i.mkdirSync(r.join(e.outDir,`modules`),{recursive:!0}),i.mkdirSync(r.join(e.outDir,`libraries`),{recursive:!0}),i.mkdirSync(r.join(e.outDir,`types`),{recursive:!0}),i.mkdirSync(e.reportsDir,{recursive:!0}),wt(e.definitions),Ct(e),Ft(e),jt(e)}function Xt(e){if(r.resolve(e.outDir)===r.resolve(e.rootDir))throw Error(`Archicat outDir cannot be the project root.`)}function Zt(){return{name:`doctor`,async run(e){let t=qe(await e.getProject());if(t.length===0)return en(`doctor`,`Project diagnostics passed`);let n=t.some(e=>e.severity===`error`);return{exitCode:+!!n,lines:[{kind:n?`error`:`warning`,label:`doctor`,message:n?`Project diagnostics failed`:`Project diagnostics completed with warnings`},...t.map(e=>({kind:e.severity===`error`?`error`:`warning`,message:` ${e.message}`}))]}}}}function Qt(){return{name:`validate`,async run(e){let t=ut(await e.getProject());return t.length===0?en(`validate`,`Architecture boundaries passed`):{exitCode:1,lines:[{kind:`error`,label:`validate`,message:`Architecture validation failed`},...t.map(e=>({kind:`error`,message:dt(e)}))]}}}}function $t(){return{name:`build`,async run(e){let t=await e.getProject();return Yt(t),{exitCode:0,lines:[{kind:`panel`,title:`mirrored`,rows:[{label:`modules`,value:t.modules.length},{label:`libraries`,value:t.libraries.length},{label:`apps`,value:t.apps.length}]}]}}}}function en(e,t){return{exitCode:0,lines:[{kind:`success`,label:e,message:t}]}}async function tn(e){return await M.make(`build`).use(Zt()).use(Qt()).use($t()).run(e)}async function nn(e){return await M.make(`validate`).use(Qt()).run(e)}async function rn(e){return await nn(e)}async function an(e){return await M.make(`doctor`).use(Zt()).run(e)}async function on(e){return await tn(e)}function sn(e){let t=[`Modules: ${e.modules.length}`,``];for(let n of e.modules)t.push(n.name),t.push(` api: ${n.apiTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.apiTarget),` api dependsOn`),t.push(` impl: ${n.implTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.implTarget),` impl dependsOn`),t.push(``);t.push(`Libraries: ${e.libraries.length}`),e.libraries.length>0&&t.push(``);for(let n of e.libraries)t.push(n.name),t.push(` api: ${n.apiTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.apiTarget),` api dependsOn`),t.push(` impl: ${n.implTarget}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.implTarget),` impl dependsOn`),t.push(``);t.push(`Apps: ${e.apps.length}`),e.apps.length>0&&t.push(``);for(let n of e.apps)t.push(n.name),t.push(` app: ${n.target}`),Q(t,e.graph.dependencies.filter(e=>e.from===n.target),` dependsOn`),t.push(``);return cn(t)}function Q(e,t,n){if(t.length===0){e.push(`${n}: none`);return}e.push(`${n}:`);for(let n of t){let t=n.origin===`derived`?` (derived)`:``;e.push(` ${n.to}${t}`)}}function cn(e){let t=[...e];for(;t.at(-1)===``;)t.pop();return t}async function ln(e){return{exitCode:0,lines:sn(await Ue(e.config)).map(e=>({kind:`info`,message:e}))}}async function un(e=process.argv.slice(2)){let[t,...n]=e;try{let e=await dn(t,hn(n));if(!e)return;fn(e),process.exitCode=e.exitCode}catch(e){s.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}async function dn(e,t){switch(e){case`build`:return await tn(t);case`generate`:return await on(t);case`validate`:return await nn(t);case`check`:return await rn(t);case`graph`:return await ln(t);case`doctor`:return await an(t);case`help`:case`--help`:case`-h`:case void 0:mn();return;default:return s.error(`Unknown command: ${e}`),mn(),{exitCode:1,lines:[]}}}function fn(e){for(let t of e.lines)pn(t)}function pn(e){switch(e.kind){case`title`:s.title(e.product,e.command,e.rows??[]);return;case`panel`:s.panel(e.title,e.rows,e.badge);return;case`success`:s.success($(e));return;case`info`:if(e.message.length===0){s.emptyLine();return}s.info($(e));return;case`warning`:s.warn($(e));return;case`error`:s.error($(e));return}}function $(e){return e.label?s.step(e.label,e.message):e.message}function mn(){s.log([`ArchiCat`,``,`Usage:`,` archicat build [--config archicat.config.ts]`,` archicat validate [--config archicat.config.ts]`,` archicat graph [--config archicat.config.ts]`,` archicat doctor [--config archicat.config.ts]`,``,`Aliases:`,` archicat generate -> archicat build`,` archicat check -> archicat validate`,``].join(`
|
|
34
|
+
`))}function hn(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}export{un as runMain};
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archicat",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"description": "Modular mirroring (M²) for clean architecture.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"m2",
|
|
7
|
-
"
|
|
7
|
+
"mirroring",
|
|
8
|
+
"modular",
|
|
8
9
|
"module-system",
|
|
9
|
-
"clean-architecture"
|
|
10
|
-
"architecture"
|
|
10
|
+
"clean-architecture"
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"author": "Simon Rastislav Kovačič",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"consola": "3.4.2",
|
|
41
42
|
"jiti": "2.7.0",
|
|
42
43
|
"typescript": "6.0.3"
|
|
43
44
|
},
|
|
@@ -56,5 +57,5 @@
|
|
|
56
57
|
"publishConfig": {
|
|
57
58
|
"registry": "https://registry.npmjs.org/"
|
|
58
59
|
},
|
|
59
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "7a5c7a37c3c277cd3c72ebfe80a9ff65920bf95a"
|
|
60
61
|
}
|