archicat 0.0.4 → 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 +0 -1
- package/dist/cli/index.mjs +8 -9
- package/package.json +2 -2
package/README.md
CHANGED
package/dist/cli/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import e from"node:path";import t from"node:fs";import{createJiti as n}from"jiti";import r from"typescript";const i=Object.freeze({root:`.`,outDir:`.archicat`,reportDir:`archicat-report`,prefixes:Object.freeze({module:`@module`,library:`@library`}),modules:Object.freeze({include:Object.freeze([`./src/modules`])}),libraries:Object.freeze({include:Object.freeze([])})});async function a(n=`archicat.config.ts`){let r=process.cwd(),i=e.resolve(r,n);if(!t.existsSync(i))throw Error(`Archicat config was not found: ${i}`);let a=await l(i,r);ne(a,i);let o=ee(a),s=e.resolve(r,o.root),c=e.resolve(s,o.outDir),u=e.resolve(s,o.reportDir),d=te(s,o.tsconfig);return{configFilePath:i,rootDir:s,outDir:c,reportDir:u,...d?{tsconfigPath:d}:{},config:a,resolvedConfig:o}}async function o(t){let n=await l(t,e.dirname(t));return u(n,t,`module`),{kind:`module`,contractFilePath:t,definitionDir:e.dirname(t),contract:n}}async function s(t){let n=await l(t,e.dirname(t));return u(n,t,`library`),{kind:`library`,contractFilePath:t,definitionDir:e.dirname(t),contract:n}}async function c(e,t){switch(t){case`module`:return o(e);case`library`:return s(e)}}async function l(e,t){return await n(t,{interopDefault:!0,extensions:[`.js`,`.cjs`,`.mjs`,`.ts`,`.cts`,`.mts`,`.json`]}).import(e,{default:!0})}function ee(e){return{root:e.root??i.root,outDir:e.outDir??i.outDir,reportDir:e.reportDir??i.reportDir,...e.tsconfig===void 0?{}:{tsconfig:e.tsconfig},prefixes:{module:e.prefixes?.module??i.prefixes.module,library:e.prefixes?.library??i.prefixes.library},modules:{include:[...e.modules?.include??i.modules.include]},libraries:{include:[...e.libraries?.include??i.libraries.include]}}}function te(n,r){if(r){let i=e.resolve(n,r);if(!t.existsSync(i))throw Error(`Configured Archicat tsconfig was not found: ${i}`);return i}return[`tsconfig.base.json`,`tsconfig.json`].map(t=>e.join(n,t)).find(e=>t.existsSync(e))}function ne(e,t){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat config: ${t}`);let n=e;d(n.root,`root`,t),d(n.outDir,`outDir`,t),d(n.reportDir,`reportDir`,t),d(n.tsconfig,`tsconfig`,t),f(n.modules?.include,`modules.include`,t),f(n.libraries?.include,`libraries.include`,t),p(n.prefixes?.module,`prefixes.module`,t),p(n.prefixes?.library,`prefixes.library`,t)}function u(e,t,n){if(typeof e!=`object`||!e)throw Error(`Invalid Archicat ${n} definition: ${t}`);let r=e;if(r.kind!==n)throw Error(`Archicat ${n} file must export define${re(n)}(...): ${t}`);if(typeof r.id!=`string`||r.id.trim()===``)throw Error(`Archicat ${n} must define a non-empty id: ${t}`);if(d(r.api,`api`,t),n===`module`&&d(r.impl,`impl`,t),!Array.isArray(r.dependencies))throw Error(`Archicat ${n} dependencies must be an array: ${t}`)}function d(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``))throw Error(`Archicat ${t} must be a non-empty string when defined: ${n}`)}function f(e,t,n){if(e!==void 0&&(!Array.isArray(e)||e.some(e=>typeof e!=`string`||e.trim()===``)))throw Error(`Archicat config ${t} must be an array of non-empty strings: ${n}`)}function p(e,t,n){if(e!==void 0&&(typeof e!=`string`||e.trim()===``||e.includes(`*`)||e.endsWith(`/`)))throw Error(`Archicat config ${t} must be a non-empty prefix without wildcard or trailing slash: ${n}`)}function re(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}function m(e,t,n){let r=t.flatMap(t=>ie(e,t,n));return Array.from(new Set(r)).sort((e,t)=>e.localeCompare(t))}function ie(n,r,i){let a=e.resolve(n,r);if(r.includes(`*`))return ae(n,r).filter(t=>e.basename(t)===i);if(!t.existsSync(a))return[];let o=t.statSync(a);return o.isFile()?e.basename(a)===i?[a]:[]:o.isDirectory()?h(a,i):[]}function h(n,r){let i=[],a=t.readdirSync(n,{withFileTypes:!0});for(let t of a){if(se(t.name))continue;let a=e.join(n,t.name);if(t.isDirectory()){i.push(...h(a,r));continue}t.isFile()&&t.name===r&&i.push(a)}return i}function ae(n,r){let i=e.resolve(n,r).split(e.sep);if(i.filter(e=>e.includes(`*`)).length!==1)throw Error(`Archicat supports exactly one wildcard segment per include pattern: ${r}`);let a=i.findIndex(e=>e.includes(`*`)),o=i.slice(0,a).join(e.sep)||e.sep,s=i[a]??`*`,c=i.slice(a+1),l=oe(s);return t.existsSync(o)?t.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).filter(e=>l.test(e.name)).map(t=>e.join(o,t.name,...c)).filter(e=>t.existsSync(e)&&t.statSync(e).isFile()):[]}function oe(e){let t=e.replace(/[.+?^${}()|[\]\\]/gu,`\\$&`).replace(/\*/gu,`.*`);return RegExp(`^${t}$`,`u`)}function se(e){return[`node_modules`,`.git`,`.archicat`,`archicat-report`,`dist`,`build`,`coverage`].includes(e)}function ce(e,t){let n=t.filter(e=>e.kind===`module`).map(t=>le(e,t)),r=t.filter(e=>e.kind===`library`).map(t=>ue(e,t)),i=[...n,...r];de(i);let a=_(i);return fe(i,a.targets),pe(i),{rootDir:e.rootDir,outDir:e.outDir,reportDir:e.reportDir,...e.tsconfigPath?{tsconfigPath:e.tsconfigPath}:{},configFilePath:e.configFilePath,config:e.resolvedConfig,modules:n,libraries:r,definitions:i,graph:a}}function le(t,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;v(r.id,i,`module`);let o=r.api?g(a,r.api,`api`,r.id):void 0,s=r.impl?g(a,r.impl,`impl`,r.id):void 0,c=`${t.resolvedConfig.prefixes.module}/${r.id}`;return{kind:`module`,id:r.id,apiTarget:`module.${r.id}.api`,implTarget:`module.${r.id}.impl`,alias:c,aliasGlob:`${c}/*`,dependencies:[...r.dependencies],contractFilePath:i,definitionDir:a,apiRootPath:o,implRootPath:s,mirrorApiRootPath:e.join(t.outDir,`modules`,r.id,`api`),mirrorImplRootPath:e.join(t.outDir,`modules`,r.id,`impl`)}}function ue(t,n){let{contract:r,contractFilePath:i,definitionDir:a}=n;v(r.id,i,`library`);let o=r.api?g(a,r.api,`api`,r.id):void 0,s=`${t.resolvedConfig.prefixes.library}/${r.id}`;return{kind:`library`,id:r.id,apiTarget:`library.${r.id}.api`,alias:s,aliasGlob:`${s}/*`,dependencies:[...r.dependencies],contractFilePath:i,definitionDir:a,apiRootPath:o,mirrorApiRootPath:e.join(t.outDir,`libraries`,r.id,`api`)}}function g(n,r,i,a){let o=e.resolve(n,r);if(!t.existsSync(o))throw Error(`Definition "${a}" declares ${i} root that does not exist: ${o}`);if(!t.statSync(o).isDirectory())throw Error(`Definition "${a}" declares ${i} root that is not a directory: ${o}`);return o}function _(e){let t=e.flatMap(e=>e.kind===`module`?[{key:e.apiTarget,kind:e.kind,id:e.id,surface:`api`},{key:e.implTarget,kind:e.kind,id:e.id,surface:`impl`}]:[{key:e.apiTarget,kind:e.kind,id:e.id,surface:`api`}]),n=e.flatMap(e=>{let t=e.kind===`module`?e.implTarget:e.apiTarget;return e.dependencies.map(e=>({from:t,to:e,implicit:!1}))});return{targets:t,dependencies:[...e.filter(e=>e.kind===`module`).map(e=>({from:e.implTarget,to:e.apiTarget,implicit:!0})),...n]}}function v(e,t,n){if(!/^[a-z][a-z0-9-]*$/u.test(e))throw Error(`Invalid Archicat ${n} id "${e}" in ${t}. Use ^[a-z][a-z0-9-]*$`)}function de(e){let t=new Map;for(let n of e){let e=`${n.kind}.${n.id}`,r=t.get(e);if(r)throw Error(`Duplicate Archicat ${n.kind} id "${n.id}" in ${r} and ${n.contractFilePath}`);t.set(e,n.contractFilePath)}}function fe(e,t){let n=new Set(t.map(e=>e.key));for(let r of e)for(let e of r.dependencies){if(!n.has(e))throw Error(`${y(r)} declares unknown dependency "${e}".`);let i=t.find(t=>t.key===e);if(i&&i.kind===r.kind&&i.id===r.id)throw Error(`${y(r)} cannot depend on itself: ${e}`)}}function pe(e){let t=new Map(e.filter(e=>e.kind===`module`).map(e=>[e.apiTarget,e])),n=new Set,r=new Set,i=(e,a)=>{if(!r.has(e.id)){if(n.has(e.id))throw Error(`Cyclic Archicat module dependency detected: ${[...a,e.id].join(` -> `)}`);n.add(e.id);for(let n of e.dependencies){let r=t.get(n);r&&i(r,[...a,e.id])}n.delete(e.id),r.add(e.id)}};for(let e of t.values())i(e,[])}function y(e){return`${e.kind} "${e.id}"`}async function b(e){let t=await a(e),n=m(t.rootDir,t.resolvedConfig.modules.include,`archicat.module.ts`),r=m(t.rootDir,t.resolvedConfig.libraries.include,`archicat.library.ts`);if(n.length===0)throw Error(`No Archicat module definitions matched modules.include.`);return ce(t,[...await Promise.all(n.map(e=>c(e,`module`))),...await Promise.all(r.map(e=>c(e,`library`)))])}function x(t){return t.split(e.sep).join(`/`)}function me(t,n){let r=e.dirname(t),i=e.parse(n),a=e.join(i.dir,i.name),o=x(e.relative(r,a));return o.startsWith(`.`)||(o=`./${o}`),`${o}.js`}function he(t,n){let r=e.relative(n,t);return r===``||!!r&&!r.startsWith(`..`)&&!e.isAbsolute(r)}function S(e){return e.replace(/\.(?:js|mjs|cjs|ts|mts|cts|tsx)$/u,``)}function C(t,n){return x(e.relative(t,n))}function w(e){return t.existsSync(e)?t.statSync(e).isFile()?T(e)?[e]:[]:E(e).filter(T).sort((e,t)=>e.localeCompare(t)):[]}function T(e){return/\.(?:ts|mts|cts|tsx)$/u.test(e)&&!/\.d\.(?:ts|mts|cts)$/u.test(e)}function E(n){let r=[],i=t.readdirSync(n,{withFileTypes:!0});for(let t of i){let i=e.join(n,t.name);if(t.isDirectory()){r.push(...E(i));continue}t.isFile()&&r.push(i)}return r}function D(e){let n=r.createSourceFile(e,t.readFileSync(e,`utf8`),r.ScriptTarget.Latest,!0),i=[],a=e=>{if(r.isImportDeclaration(e)&&r.isStringLiteral(e.moduleSpecifier)&&i.push({moduleSpecifier:e.moduleSpecifier.text,kind:`import`}),r.isExportDeclaration(e)&&e.moduleSpecifier&&r.isStringLiteral(e.moduleSpecifier)&&i.push({moduleSpecifier:e.moduleSpecifier.text,kind:`export`}),r.isCallExpression(e)&&e.expression.kind===r.SyntaxKind.ImportKeyword){let[t]=e.arguments;t&&r.isStringLiteral(t)&&i.push({moduleSpecifier:t.text,kind:`dynamic-import`})}r.forEachChild(e,a)};return a(n),i}function O(e){let n=r.createSourceFile(e,t.readFileSync(e,`utf8`),r.ScriptTarget.Latest,!0),i=!1,a=e=>{if(!i){if(r.isExportAssignment(e)&&!e.isExportEquals){i=!0;return}if(k(e)){i=!0;return}if(r.isExportDeclaration(e)&&e.exportClause&&r.isNamedExports(e.exportClause))for(let t of e.exportClause.elements){let e=t.name.text,n=t.propertyName?.text;if(e==="default"||n==="default"){i=!0;return}}r.forEachChild(e,a)}};return a(n),i}function k(e){let t=r.canHaveModifiers(e)?r.getModifiers(e):void 0;if(!t)return!1;let n=t.some(e=>e.kind===r.SyntaxKind.ExportKeyword),i=t.some(e=>e.kind===r.SyntaxKind.DefaultKeyword);return n&&i}async function A(e){return j(await b(e))}function j(e){let t=[],n=e.definitions.flatMap(e=>M(e));for(let r of n){let n=I(e.definitions,r);if(n)for(let i of D(r)){let a=N(e,n,r,i.moduleSpecifier);a&&t.push(a)}}return t}function M(e){return e.kind===`module`?[...e.apiRootPath?w(e.apiRootPath):[],...e.implRootPath?w(e.implRootPath):[]]:e.apiRootPath?w(e.apiRootPath):[]}function N(e,t,n,r){let i=R(e,r);if(i)return i.kind===t.kind&&i.id===t.id||t.dependencies.includes(i.target)?void 0:z(e,n,r,`${B(t.kind)} "${t.id}" imports "${i.target}" but does not declare it in dependencies.`);if(r.startsWith(`.`)||r.startsWith(`/`))return P(e,t,n,r)}function P(e,t,n,r){let i=F(n,r),a=I(e.definitions,i);if(!(!a||a.kind===t.kind&&a.id===t.id))return z(e,n,r,`${B(t.kind)} "${t.id}" imports ${a.kind} "${a.id}" through a source path. Use "${a.alias}" instead.`)}function F(t,n){return S(n.startsWith(`/`)?n:e.resolve(e.dirname(t),n))}function I(e,t){let n=S(t);return e.find(e=>L(e).filter(e=>!!e).some(e=>he(n,S(e))))}function L(e){return e.kind===`module`?[e.apiRootPath,e.implRootPath,e.definitionDir]:[e.apiRootPath,e.definitionDir]}function R(e,t){for(let n of e.definitions)if(t===n.alias||t.startsWith(`${n.alias}/`))return{kind:n.kind,id:n.id,target:n.apiTarget}}function z(e,t,n,r){return{filePath:C(e.rootDir,t),importPath:n,message:r}}function B(e){return`${e.charAt(0).toUpperCase()}${e.slice(1)}`}async function ge(e){let t=await b(e);return[..._e(t),...ve(t),...ye(t)]}function _e(n){let r=e.join(n.outDir,`tsconfig.json`);return t.existsSync(r)?[]:[{severity:`warning`,message:`Generated tsconfig does not exist yet: ${r}. Run archicat generate.`}]}function ve(n){let r=e.join(n.rootDir,`tsconfig.json`);if(!t.existsSync(r))return[{severity:`warning`,message:`Root tsconfig.json was not found: ${r}`}];try{let e=JSON.parse(t.readFileSync(r,`utf8`)),n=[];return e.extends!==`./.archicat/tsconfig.json`&&e.extends!==`.archicat/tsconfig.json`&&n.push({severity:`warning`,message:`Root tsconfig.json should extend ./.archicat/tsconfig.json for Archicat aliases to work like Nuxt.`}),(e.compilerOptions?.rootDir===`src`||e.compilerOptions?.rootDir===`./src`)&&n.push({severity:`warning`,message:`compilerOptions.rootDir is set to src. Generated .archicat files live outside src and may break tsc.`}),n}catch(e){return[{severity:`warning`,message:`Failed to parse root tsconfig.json: ${e}`}]}}function ye(n){let r=[];for(let i of n.modules){let n=e.join(i.definitionDir,`api`),a=e.join(i.definitionDir,`impl`);!i.apiRootPath&&t.existsSync(n)&&r.push({severity:`warning`,message:`Module "${i.id}" has a physical api directory but its contract omits api. Archicat treats the public API as empty.`}),!i.implRootPath&&t.existsSync(a)&&r.push({severity:`warning`,message:`Module "${i.id}" has a physical impl directory but its contract omits impl. Archicat treats the implementation as no-op.`})}return r}function V(e){t.existsSync(e)&&t.rmSync(e,{recursive:!0,force:!0}),t.mkdirSync(e,{recursive:!0})}function H(n,r){t.mkdirSync(e.dirname(n),{recursive:!0}),t.writeFileSync(n,r,`utf8`)}function U(e,t){H(e,`${JSON.stringify(t,null,2)}\n`)}function W(t){let n=`declare module 'archicat' {
|
|
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
2
|
interface ArchicatProjectGraph {
|
|
3
3
|
${t.graph.targets.map(e=>` '${e.key}': true;`).join(`
|
|
4
4
|
`)}
|
|
@@ -6,9 +6,9 @@ ${t.graph.targets.map(e=>` '${e.key}': true;`).join(`
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export {};
|
|
9
|
-
`;
|
|
10
|
-
`);return}let n=
|
|
11
|
-
`)}function
|
|
9
|
+
`;W(e.join(t.outDir,`types`,`graph.d.ts`),n)}function Te(e){for(let t of e)switch(t.kind){case`module`:Ee(t);break;case`library`:K(t);break}}function Ee(e){K(e),De(e)}function K(t){if(!t.apiRootPath){W(e.join(t.mirrorApiRootPath,`index.ts`),`${J()}export {};
|
|
10
|
+
`);return}let n=O(t.apiRootPath),r=new Set;for(let i of n){let n=T(e.relative(t.apiRootPath,i));r.add(n),q(e.join(t.mirrorApiRootPath,n),i)}r.has(`index.ts`)||W(e.join(t.mirrorApiRootPath,`index.ts`),`${J()}export {};
|
|
11
|
+
`)}function De(t){let n=t.implRootPath?Oe(t.implRootPath):void 0;if(!n){let n=`${J()}
|
|
12
12
|
export const ArchicatModuleImplementation = {
|
|
13
13
|
id: '${t.id}',
|
|
14
14
|
assemblies: [],
|
|
@@ -17,9 +17,8 @@ export const ArchicatModuleImplementation = {
|
|
|
17
17
|
} as const;
|
|
18
18
|
|
|
19
19
|
export default ArchicatModuleImplementation;
|
|
20
|
-
`;
|
|
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()}
|
|
21
21
|
export * from '${n}';
|
|
22
|
-
${r}`)}function
|
|
23
|
-
`}function
|
|
24
|
-
`)
|
|
25
|
-
`))}function Q(e){console.log(`✓ ${e}`)}function Ve(e){console.warn(`! ${e}`)}function $(e){console.error(`✗ ${e}`)}export{ze as runMain};
|
|
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/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
|
}
|