@archest/vitest 1.0.0
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/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +596 -0
- package/dist/index.mjs.map +1 -0
- package/dist/src/core/ClassLocator.d.ts +20 -0
- package/dist/src/core/FileLocator.d.ts +15 -0
- package/dist/src/core/FunctionLocator.d.ts +15 -0
- package/dist/src/core/LayerLocator.d.ts +23 -0
- package/dist/src/core/Project.d.ts +20 -0
- package/dist/src/core/PropertyLocator.d.ts +12 -0
- package/dist/src/core/SliceLocator.d.ts +10 -0
- package/dist/src/core/types.d.ts +4 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/matchers/index.d.ts +15 -0
- package/package.json +44 -0
- package/src/core/ClassLocator.ts +226 -0
- package/src/core/FileLocator.ts +168 -0
- package/src/core/FunctionLocator.ts +105 -0
- package/src/core/LayerLocator.ts +119 -0
- package/src/core/Project.ts +171 -0
- package/src/core/PropertyLocator.ts +50 -0
- package/src/core/SliceLocator.ts +92 -0
- package/src/core/types.ts +4 -0
- package/src/index.ts +9 -0
- package/src/matchers/index.ts +113 -0
- package/test/architecture.test.ts +59 -0
- package/tsconfig.json +17 -0
- package/vite.config.ts +18 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`typescript`),require(`path`),require(`vitest`)):typeof define==`function`&&define.amd?define([`exports`,`typescript`,`path`,`vitest`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.VitestArch={},e.typescript,e.path,e.vitest))})(this,function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=Object.create,a=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,u=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=s(t),c=0,u=i.length,d;c<u;c++)d=i[c],!l.call(e,d)&&d!==n&&a(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=o(t,d))||r.enumerable});return e},d=(e,t,n)=>(n=e==null?{}:i(c(e)),u(t||!e||!e.__esModule?a(n,`default`,{value:e,enumerable:!0}):n,e));t=d(t),n=d(n);var f=class{files;constructor(e,t,n){this.program=t;let r=e;if(n?.inFolder&&(r=r.filter(e=>e.fileName.includes(`/${n.inFolder}/`)||e.fileName.includes(`\\${n.inFolder}\\`))),n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>e.test(t.fileName))}this.files=r}getFileDependencies(e){let n=[],r=this.program.getCompilerOptions(),i=a=>{if(t.isImportDeclaration(a)){let i=a.moduleSpecifier.text,o=t.resolveModuleName(i,e.fileName,r,t.sys);o.resolvedModule&&o.resolvedModule.resolvedFileName&&(o.resolvedModule.isExternalLibraryImport||n.push(o.resolvedModule.resolvedFileName))}else if(t.isExportDeclaration(a)&&a.moduleSpecifier){let i=a.moduleSpecifier.text,o=t.resolveModuleName(i,e.fileName,r,t.sys);o.resolvedModule&&o.resolvedModule.resolvedFileName&&(o.resolvedModule.isExternalLibraryImport||n.push(o.resolvedModule.resolvedFileName))}t.forEachChild(a,i)};return i(e),n}checkDependOnFilesInFolder(e,t){let n=[];for(let r of this.files){let i=this.getFileDependencies(r).some(t=>t.includes(`/${e}/`)||t.includes(`\\${e}\\`));t&&i?n.push(`File ${r.fileName} depends on files in ${e}, but it shouldn't.`):!t&&!i&&n.push(`File ${r.fileName} does not depend on files in ${e}, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
|
|
2
|
+
`)}}checkBeFreeOfCycles(e){let t=[],n=new Set(this.files.map(e=>e.fileName)),r=new Map;for(let e of this.files){let t=e.fileName,i=this.getFileDependencies(e).filter(e=>n.has(e));r.set(t,i)}let i=new Set,a=new Set,o=[],s=(e,t)=>{if(a.has(e)){let n=t.indexOf(e),r=[...t.slice(n),e].join(`->`);return o.some(e=>e.join(`->`)===r)||o.push([...t.slice(n),e]),!0}if(i.has(e))return!1;i.add(e),a.add(e),t.push(e);let n=r.get(e)||[];for(let e of n)s(e,t);return a.delete(e),t.pop(),!1};for(let e of r.keys())i.has(e)||s(e,[]);if(e&&o.length===0)t.push(`Expected cyclic dependencies, but found none.`);else if(!e&&o.length>0)for(let e of o)t.push(`Cycle detected: ${e.join(` -> `)}`);return{pass:t.length===0,message:()=>t.join(`
|
|
3
|
+
`)}}checkMatchNamePattern(e,t){let n=[],r=typeof e==`string`?new RegExp(e):e;for(let i of this.files){let a=r.test(i.fileName);t&&a?n.push(`File ${i.fileName} matches pattern ${e}, but it shouldn't.`):!t&&!a&&n.push(`File ${i.fileName} does not match pattern ${e}, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
|
|
4
|
+
`)}}},p=class{classes;constructor(e,n,r){this.program=n;let i=e;if(r?.inFolder&&(i=i.filter(e=>{let t=e.getSourceFile();return t.fileName.includes(`/${r.inFolder}/`)||t.fileName.includes(`\\${r.inFolder}\\`)})),r?.matchNamePattern){let e=typeof r.matchNamePattern==`string`?new RegExp(r.matchNamePattern):r.matchNamePattern;i=i.filter(t=>{let n=t.name?.text;return n&&e.test(n)})}if(r?.withDecorator&&(i=i.filter(e=>{let n=t.canHaveDecorators(e)?t.getDecorators(e):void 0,i=!1;if(n)for(let e of n){let n=e.expression,a=``;t.isIdentifier(n)?a=n.text:t.isCallExpression(n)&&t.isIdentifier(n.expression)&&(a=n.expression.text),a===r.withDecorator&&(i=!0)}return i})),r?.extending&&(i=i.filter(e=>{if(e.heritageClauses){for(let n of e.heritageClauses)if(n.token===t.SyntaxKind.ExtendsKeyword){for(let e of n.types)if(t.isIdentifier(e.expression)&&e.expression.text===r.extending)return!0}}return!1})),r?.implementing&&(i=i.filter(e=>{if(e.heritageClauses){for(let n of e.heritageClauses)if(n.token===t.SyntaxKind.ImplementsKeyword){for(let e of n.types)if(t.isIdentifier(e.expression)&&e.expression.text===r.implementing)return!0}}return!1})),r?.havingModifier){let e;switch(r.havingModifier){case`export`:e=t.SyntaxKind.ExportKeyword;break;case`default`:e=t.SyntaxKind.DefaultKeyword;break;case`abstract`:e=t.SyntaxKind.AbstractKeyword;break;default:throw Error(`Modifier ${r.havingModifier} is not fully supported.`)}i=i.filter(n=>{let r=t.canHaveModifiers(n)?t.getModifiers(n):void 0;return r&&r.some(t=>t.kind===e)})}this.classes=i}checkResideInFolder(e,t){let n=[];for(let r of this.classes){let i=r.name?.text||`Anonymous Class`,a=r.getSourceFile(),o=a.fileName.includes(`/${e}/`)||a.fileName.includes(`\\${e}\\`);t&&o?n.push(`Class ${i} resides in ${e}, but it shouldn't.`):!t&&!o&&n.push(`Class ${i} does not reside in ${e}, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
|
|
5
|
+
`)}}checkMatchNamePattern(e,t){let n=[],r=typeof e==`string`?new RegExp(e):e;for(let i of this.classes){let a=i.name?.text,o=a&&r.test(a);t&&o?n.push(`Class ${a} matches pattern ${e}, but it shouldn't.`):!t&&!o&&n.push(`Class ${a||`Anonymous`} does not match pattern ${e}, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
|
|
6
|
+
`)}}checkExtendClass(e,n){let r=[];for(let i of this.classes){let a=i.name?.text||`Anonymous`,o=!1;if(i.heritageClauses){for(let n of i.heritageClauses)if(n.token===t.SyntaxKind.ExtendsKeyword){for(let r of n.types)if(t.isIdentifier(r.expression)&&r.expression.text===e){o=!0;break}}}n&&o?r.push(`Class ${a} extends ${e}, but it shouldn't.`):!n&&!o&&r.push(`Class ${a} does not extend ${e}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
7
|
+
`)}}checkImplementInterface(e,n){let r=[];for(let i of this.classes){let a=i.name?.text||`Anonymous`,o=!1;if(i.heritageClauses){for(let n of i.heritageClauses)if(n.token===t.SyntaxKind.ImplementsKeyword){for(let r of n.types)if(t.isIdentifier(r.expression)&&r.expression.text===e){o=!0;break}}}n&&o?r.push(`Class ${a} implements ${e}, but it shouldn't.`):!n&&!o&&r.push(`Class ${a} does not implement ${e}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
8
|
+
`)}}checkHaveModifier(e,n){let r;switch(e){case`export`:r=t.SyntaxKind.ExportKeyword;break;case`default`:r=t.SyntaxKind.DefaultKeyword;break;case`abstract`:r=t.SyntaxKind.AbstractKeyword;break;default:throw Error(`Modifier ${e} is not fully supported.`)}let i=[];for(let a of this.classes){let o=a.name?.text||`Anonymous`,s=t.canHaveModifiers(a)?t.getModifiers(a):void 0,c=s&&s.some(e=>e.kind===r);n&&c?i.push(`Class ${o} has modifier ${e}, but it shouldn't.`):!n&&!c&&i.push(`Class ${o} does not have modifier ${e}, but it should.`)}return{pass:i.length===0,message:()=>i.join(`
|
|
9
|
+
`)}}},m=class{files;layers=new Map;assertions=[];constructor(e,t){this.program=t,this.files=e}layer(e,t){return this.layers.set(e,t),this}whereLayer(e){if(!this.layers.has(e))throw Error(`Layer ${e} is not defined`);return new h(this,e)}addAssertion(e){this.assertions.push(e)}getFiles(){return this.files}getLayerPattern(e){return this.layers.get(e)}getFileDependencies(e){let n=[],r=this.program.getCompilerOptions(),i=a=>{if(t.isImportDeclaration(a)){let i=a.moduleSpecifier.text,o=t.resolveModuleName(i,e.fileName,r,t.sys);o.resolvedModule&&o.resolvedModule.resolvedFileName&&!o.resolvedModule.isExternalLibraryImport&&n.push(o.resolvedModule.resolvedFileName)}else if(t.isExportDeclaration(a)&&a.moduleSpecifier){let i=a.moduleSpecifier.text,o=t.resolveModuleName(i,e.fileName,r,t.sys);o.resolvedModule&&o.resolvedModule.resolvedFileName&&!o.resolvedModule.isExternalLibraryImport&&n.push(o.resolvedModule.resolvedFileName)}t.forEachChild(a,i)};return i(e),n}check(){let e=[];for(let t of this.assertions)e.push(...t(this.files));return{pass:e.length===0,message:()=>e.join(`
|
|
10
|
+
`)}}},h=class{constructor(e,t){this.parent=e,this.targetLayer=t}shouldNotBeAccessedByAnyLayer(){return this.parent.addAssertion(e=>{let t=[],n=this.parent.getLayerPattern(this.targetLayer);for(let r of e){let e=r.fileName;!e.includes(`/${n}/`)&&!e.includes(`\\${n}\\`)&&this.parent.getFileDependencies(r).some(e=>e.includes(`/${n}/`)||e.includes(`\\${n}\\`))&&t.push(`File ${e} accesses layer ${this.targetLayer} but it shouldn't.`)}return t}),this.parent}shouldOnlyBeAccessedBy(...e){return this.parent.addAssertion(t=>{let n=[],r=this.parent.getLayerPattern(this.targetLayer),i=e.map(e=>this.parent.getLayerPattern(e));for(let a of t){let t=a.fileName,o=i.some(e=>t.includes(`/${e}/`)||t.includes(`\\${e}\\`));!t.includes(`/${r}/`)&&!t.includes(`\\${r}\\`)&&!o&&this.parent.getFileDependencies(a).some(e=>e.includes(`/${r}/`)||e.includes(`\\${r}\\`))&&n.push(`File ${t} accesses layer ${this.targetLayer} but only ${e.join(`, `)} are allowed.`)}return n}),this.parent}},g=class{functions;constructor(e,n,r){this.program=n;let i=e;if(r?.inFolder&&(i=i.filter(e=>{let t=e.getSourceFile();return t.fileName.includes(`/${r.inFolder}/`)||t.fileName.includes(`\\${r.inFolder}\\`)})),r?.matchNamePattern){let e=typeof r.matchNamePattern==`string`?new RegExp(r.matchNamePattern):r.matchNamePattern;i=i.filter(n=>n.name&&t.isIdentifier(n.name)&&e.test(n.name.text))}r?.isTopLevel&&(i=i.filter(e=>t.isSourceFile(e.parent))),this.functions=i}checkHaveModifier(e,n){let r;switch(e){case`export`:r=t.SyntaxKind.ExportKeyword;break;case`async`:r=t.SyntaxKind.AsyncKeyword;break;case`private`:r=t.SyntaxKind.PrivateKeyword;break;case`public`:r=t.SyntaxKind.PublicKeyword;break;default:throw Error(`Modifier ${e} is not fully supported.`)}let i=[];for(let a of this.functions){let o=a.name&&t.isIdentifier(a.name)?a.name.text:`Anonymous Function`,s=t.canHaveModifiers(a)?t.getModifiers(a):void 0,c=s&&s.some(e=>e.kind===r);n&&c?i.push(`Function ${o} has modifier ${e}, but it shouldn't.`):!n&&!c&&i.push(`Function ${o} does not have modifier ${e}, but it should.`)}return{pass:i.length===0,message:()=>i.join(`
|
|
11
|
+
`)}}checkHaveExplicitReturnType(e){let n=[];for(let r of this.functions){let i=r.name&&t.isIdentifier(r.name)?r.name.text:`Anonymous Function`,a=!!r.type;e&&a?n.push(`Function ${i} has an explicit return type, but it shouldn't.`):!e&&!a&&n.push(`Function ${i} does not have an explicit return type, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
|
|
12
|
+
`)}}checkMatchNamePattern(e,n){let r=[],i=typeof e==`string`?new RegExp(e):e;for(let a of this.functions){let o=a.name&&t.isIdentifier(a.name)?a.name.text:void 0,s=o&&i.test(o);n&&s?r.push(`Function ${o} matches pattern ${e}, but it shouldn't.`):!n&&!s&&r.push(`Function ${o||`Anonymous Function`} does not match pattern ${e}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
13
|
+
`)}}},_=class{properties;constructor(e,n,r){this.program=n;let i=e;if(r?.inFolder&&(i=i.filter(e=>{let t=e.getSourceFile();return t.fileName.includes(`/${r.inFolder}/`)||t.fileName.includes(`\\${r.inFolder}\\`)})),r?.matchNamePattern){let e=typeof r.matchNamePattern==`string`?new RegExp(r.matchNamePattern):r.matchNamePattern;i=i.filter(n=>t.isIdentifier(n.name)&&e.test(n.name.text))}this.properties=i}checkBeReadonly(e){let n=[];for(let r of this.properties){let i=t.isIdentifier(r.name)?r.name.text:`Anonymous Property`,a=t.canHaveModifiers(r)?t.getModifiers(r):void 0,o=a&&a.some(e=>e.kind===t.SyntaxKind.ReadonlyKeyword);e&&o?n.push(`Property ${i} is readonly, but it shouldn't be.`):!e&&!o&&n.push(`Property ${i} is not readonly, but it should be.`)}return{pass:n.length===0,message:()=>n.join(`
|
|
14
|
+
`)}}},v=class{slicePattern;sliceIds=new Set;sliceFiles=new Map;constructor(e,t,n){this.program=t;let r=n.replace(/[.+?^${}()|[\]\\]/g,`\\$&`).replace(/\*/g,`([^/\\\\]+)`);this.slicePattern=new RegExp(r);for(let t of e){let e=t.fileName.match(this.slicePattern);if(e&&e[1]){let n=e[1];this.sliceIds.add(n),this.sliceFiles.has(n)||this.sliceFiles.set(n,[]),this.sliceFiles.get(n).push(t)}}}checkBeFreeOfCycles(e){let n=new Map;for(let e of this.sliceIds)n.set(e,new Set);for(let[e,r]of this.sliceFiles.entries())for(let i of r)t.forEachChild(i,r=>{if(t.isImportDeclaration(r)&&r.moduleSpecifier&&t.isStringLiteral(r.moduleSpecifier)){let a=r.moduleSpecifier.text,o=t.resolveModuleName(a,i.fileName,this.program.getCompilerOptions(),t.sys);if(o.resolvedModule&&o.resolvedModule.resolvedFileName){let t=o.resolvedModule.resolvedFileName.match(this.slicePattern);if(t&&t[1]){let r=t[1];r!==e&&this.sliceIds.has(r)&&n.get(e).add(r)}}}});let r=new Set,i=new Set,a=[],o=(e,t)=>{r.add(e),i.add(e);for(let s of n.get(e)||[])if(!r.has(s)){if(o(s,[...t,s]))return!0}else if(i.has(s))return a.push(`Cycle detected between slices: ${t.join(` -> `)} -> ${s}`),!0;return i.delete(e),!1};for(let e of this.sliceIds)r.has(e)||o(e,[e]);return e?{pass:a.length>0,message:()=>a.length>0?``:`Expected cycles between slices but found none.`}:{pass:a.length===0,message:()=>a.join(`
|
|
15
|
+
`)}}},y=class{program;typeChecker;constructor(e={}){let r={},i=e.tsConfigFilePath||t.findConfigFile(process.cwd(),t.sys.fileExists,`tsconfig.json`);if(i){let e=t.readConfigFile(i,t.sys.readFile),a=t.parseJsonConfigFileContent(e.config,t.sys,n.dirname(i),void 0,i,void 0,[{extension:`.vue`,isMixedContent:!0,scriptKind:t.ScriptKind.TS},{extension:`.svelte`,isMixedContent:!0,scriptKind:t.ScriptKind.TS}]);r=a.options;let o=t.createCompilerHost(r),s=o.getSourceFile,c;try{c=require(`@vue/compiler-sfc`)}catch{}o.getSourceFile=(e,n,r,i)=>{if(e.endsWith(`.vue`)){let r=t.sys.readFile(e);if(r){let i=``;if(c){let e=c.parse(r),t=e.descriptor.script,n=e.descriptor.scriptSetup;t&&(i+=t.content+`
|
|
16
|
+
`),n&&(i+=n.content+`
|
|
17
|
+
`)}else{let e=r.match(/<script[^>]*>(.*?)<\/script>/s);e&&(i=e[1])}return t.createSourceFile(e,i,n,!0,t.ScriptKind.TS)}}if(e.endsWith(`.svelte`)){let r=t.sys.readFile(e);if(r){let i=``,a=r.match(/<script[^>]*>(.*?)<\/script>/s);return a&&(i=a[1]),t.createSourceFile(e,i,n,!0,t.ScriptKind.TS)}}return s(e,n,r,i)},this.program=t.createProgram({rootNames:a.fileNames,options:r,host:o})}else throw Error(`Could not find tsconfig.json`);this.typeChecker=this.program.getTypeChecker()}getFiles(e){return new f(this.program.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`)),this.program,e)}getClasses(e){let n=this.program.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`)),r=[];for(let e of n){let n=e=>{t.isClassDeclaration(e)&&r.push(e),t.forEachChild(e,n)};n(e)}return new p(r,this.program,e)}layeredArchitecture(){return new m(this.program.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`)),this.program)}getFunctions(e){let n=this.program.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`)),r=[];for(let e of n){let n=e=>{(t.isFunctionDeclaration(e)||t.isMethodDeclaration(e)||t.isArrowFunction(e))&&r.push(e),t.forEachChild(e,n)};n(e)}return new g(r,this.program,e)}getProperties(e){let n=this.program.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`)),r=[];for(let e of n){let n=e=>{t.isPropertyDeclaration(e)&&r.push(e),t.forEachChild(e,n)};n(e)}return new _(r,this.program,e)}getSlices(e){return new v(this.program.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`)),this.program,e)}};function b(e){return new y({tsConfigFilePath:e})}function x(){r.expect.extend({toPass(e){let{pass:t,message:n}=e instanceof m?e.check():e;return{pass:this.isNot?!t:t,message:t?()=>`Expected rule not to pass`:()=>n()}},toResideInFolder(e,t){let{pass:n,message:r}=e.checkResideInFolder(t,this.isNot);return{pass:this.isNot?!n:n,message:r}},toHaveModifier(e,t){let{pass:n,message:r}=e.checkHaveModifier(t,this.isNot);return{pass:this.isNot?!n:n,message:r}},toExtendClass(e,t){let{pass:n,message:r}=e.checkExtendClass(t,this.isNot);return{pass:this.isNot?!n:n,message:r}},toImplementInterface(e,t){let{pass:n,message:r}=e.checkImplementInterface(t,this.isNot);return{pass:this.isNot?!n:n,message:r}},toHaveExplicitReturnType(e){let{pass:t,message:n}=e.checkHaveExplicitReturnType(this.isNot);return{pass:this.isNot?!t:t,message:n}},toBeReadonly(e){let{pass:t,message:n}=e.checkBeReadonly(this.isNot);return{pass:this.isNot?!t:t,message:n}},toDependOnFilesInFolder(e,t){let{pass:n,message:r}=e.checkDependOnFilesInFolder(t,this.isNot);return{pass:this.isNot?!n:n,message:r}},toBeFreeOfCycles(e){let{pass:t,message:n}=e.checkBeFreeOfCycles(this.isNot);return{pass:this.isNot?!t:t,message:n}},toMatchNamePattern(e,t){let{pass:n,message:r}=e.checkMatchNamePattern(t,this.isNot);return{pass:this.isNot?!n:n,message:r}}})}e.ClassLocator=p,e.FileLocator=f,e.FunctionLocator=g,e.LayerAssertionBuilder=h,e.LayeredArchitectureBuilder=m,e.Project=y,e.PropertyLocator=_,e.SliceLocator=v,e.parseProject=b,e.setupMatchers=x});
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/core/FileLocator.ts","../src/core/ClassLocator.ts","../src/core/LayerLocator.ts","../src/core/FunctionLocator.ts","../src/core/PropertyLocator.ts","../src/core/SliceLocator.ts","../src/core/Project.ts","../src/matchers/index.ts"],"sourcesContent":["import * as ts from 'typescript';\nimport { RuleResult } from './types';\n\nexport interface FileQueryOptions {\n inFolder?: string;\n matchNamePattern?: string | RegExp;\n}\n\nexport class FileLocator {\n public readonly files: ts.SourceFile[];\n\n constructor(sourceFiles: ts.SourceFile[], private program: ts.Program, options?: FileQueryOptions) {\n let filtered = sourceFiles;\n\n if (options?.inFolder) {\n filtered = filtered.filter((file) => file.fileName.includes(`/${options.inFolder}/`) || file.fileName.includes(`\\\\${options.inFolder}\\\\`));\n }\n if (options?.matchNamePattern) {\n const regex = typeof options.matchNamePattern === 'string' ? new RegExp(options.matchNamePattern) : options.matchNamePattern;\n filtered = filtered.filter((file) => regex.test(file.fileName));\n }\n\n this.files = filtered;\n }\n\n private getFileDependencies(sourceFile: ts.SourceFile): string[] {\n const dependencies: string[] = [];\n const compilerOptions = this.program.getCompilerOptions();\n\n const visit = (node: ts.Node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys\n );\n if (resolved.resolvedModule && resolved.resolvedModule.resolvedFileName) {\n if (!resolved.resolvedModule.isExternalLibraryImport) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys\n );\n if (resolved.resolvedModule && resolved.resolvedModule.resolvedFileName) {\n if (!resolved.resolvedModule.isExternalLibraryImport) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return dependencies;\n }\n\n checkDependOnFilesInFolder(targetFolder: string, isNot: boolean): RuleResult {\n const violations: string[] = [];\n\n for (const file of this.files) {\n const dependencies = this.getFileDependencies(file);\n \n const dependsOnTarget = dependencies.some((depPath) => depPath.includes(`/${targetFolder}/`) || depPath.includes(`\\\\${targetFolder}\\\\`));\n\n if (isNot && dependsOnTarget) {\n violations.push(`File ${file.fileName} depends on files in ${targetFolder}, but it shouldn't.`);\n } else if (!isNot && !dependsOnTarget) {\n violations.push(`File ${file.fileName} does not depend on files in ${targetFolder}, but it should.`);\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkBeFreeOfCycles(isNot: boolean): RuleResult {\n const violations: string[] = [];\n const targetedFilePaths = new Set<string>(this.files.map(f => f.fileName));\n const graph = new Map<string, string[]>();\n\n for (const file of this.files) {\n const filePath = file.fileName;\n const dependencies = this.getFileDependencies(file)\n .filter((p) => targetedFilePaths.has(p));\n \n graph.set(filePath, dependencies);\n }\n\n const visited = new Set<string>();\n const recStack = new Set<string>();\n const cycles: string[][] = [];\n\n const isCyclicUtil = (node: string, path: string[]) => {\n if (recStack.has(node)) {\n const cycleStartIndex = path.indexOf(node);\n const cycleStr = [...path.slice(cycleStartIndex), node].join('->');\n if (!cycles.some(c => c.join('->') === cycleStr)) {\n cycles.push([...path.slice(cycleStartIndex), node]);\n }\n return true;\n }\n\n if (visited.has(node)) return false;\n\n visited.add(node);\n recStack.add(node);\n path.push(node);\n\n const neighbors = graph.get(node) || [];\n for (const neighbor of neighbors) {\n isCyclicUtil(neighbor, path);\n }\n\n recStack.delete(node);\n path.pop();\n return false;\n };\n\n for (const node of graph.keys()) {\n if (!visited.has(node)) {\n isCyclicUtil(node, []);\n }\n }\n\n if (isNot && cycles.length === 0) {\n violations.push('Expected cyclic dependencies, but found none.');\n } else if (!isNot && cycles.length > 0) {\n for (const cycle of cycles) {\n violations.push(`Cycle detected: ${cycle.join(' -> ')}`);\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkMatchNamePattern(pattern: string | RegExp, isNot: boolean): RuleResult {\n const violations: string[] = [];\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n\n for (const file of this.files) {\n const matches = regex.test(file.fileName);\n\n if (isNot && matches) {\n violations.push(`File ${file.fileName} matches pattern ${pattern}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`File ${file.fileName} does not match pattern ${pattern}, but it should.`);\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n}\n","import * as ts from 'typescript';\nimport { RuleResult } from './types';\n\nexport interface ClassQueryOptions {\n inFolder?: string;\n matchNamePattern?: string | RegExp;\n withDecorator?: string;\n extending?: string;\n implementing?: string;\n havingModifier?: string;\n}\n\nexport class ClassLocator {\n public readonly classes: ts.ClassDeclaration[];\n\n constructor(classes: ts.ClassDeclaration[], private program: ts.Program, options?: ClassQueryOptions) {\n let filtered = classes;\n\n if (options?.inFolder) {\n filtered = filtered.filter((c) => {\n const sourceFile = c.getSourceFile();\n return sourceFile.fileName.includes(`/${options.inFolder}/`) || sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`);\n });\n }\n if (options?.matchNamePattern) {\n const regex = typeof options.matchNamePattern === 'string' ? new RegExp(options.matchNamePattern) : options.matchNamePattern;\n filtered = filtered.filter((c) => {\n const name = c.name?.text;\n return name && regex.test(name);\n });\n }\n if (options?.withDecorator) {\n filtered = filtered.filter((c) => {\n const decorators = ts.canHaveDecorators(c) ? ts.getDecorators(c) : undefined;\n let hasDecorator = false;\n if (decorators) {\n for (const dec of decorators) {\n const exp = dec.expression;\n let name = '';\n if (ts.isIdentifier(exp)) {\n name = exp.text;\n } else if (ts.isCallExpression(exp) && ts.isIdentifier(exp.expression)) {\n name = exp.expression.text;\n }\n if (name === options.withDecorator) {\n hasDecorator = true;\n }\n }\n }\n return hasDecorator;\n });\n }\n if (options?.extending) {\n filtered = filtered.filter((c) => {\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ExtendsKeyword) {\n for (const type of clause.types) {\n if (ts.isIdentifier(type.expression) && type.expression.text === options.extending) {\n return true;\n }\n }\n }\n }\n }\n return false;\n });\n }\n if (options?.implementing) {\n filtered = filtered.filter((c) => {\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ImplementsKeyword) {\n for (const type of clause.types) {\n if (ts.isIdentifier(type.expression) && type.expression.text === options.implementing) {\n return true;\n }\n }\n }\n }\n }\n return false;\n });\n }\n if (options?.havingModifier) {\n let targetKind: ts.SyntaxKind;\n switch (options.havingModifier) {\n case 'export': targetKind = ts.SyntaxKind.ExportKeyword; break;\n case 'default': targetKind = ts.SyntaxKind.DefaultKeyword; break;\n case 'abstract': targetKind = ts.SyntaxKind.AbstractKeyword; break;\n default:\n throw new Error(`Modifier ${options.havingModifier} is not fully supported.`);\n }\n filtered = filtered.filter((c) => {\n const modifiers = ts.canHaveModifiers(c) ? ts.getModifiers(c) : undefined;\n return modifiers && modifiers.some((m: ts.Modifier) => m.kind === targetKind);\n });\n }\n\n this.classes = filtered;\n }\n\n checkResideInFolder(targetFolder: string, isNot: boolean): RuleResult {\n const violations: string[] = [];\n for (const c of this.classes) {\n const className = c.name?.text || 'Anonymous Class';\n const sourceFile = c.getSourceFile();\n const inTargetFolder = sourceFile.fileName.includes(`/${targetFolder}/`) || sourceFile.fileName.includes(`\\\\${targetFolder}\\\\`);\n\n if (isNot && inTargetFolder) {\n violations.push(`Class ${className} resides in ${targetFolder}, but it shouldn't.`);\n } else if (!isNot && !inTargetFolder) {\n violations.push(`Class ${className} does not reside in ${targetFolder}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkMatchNamePattern(pattern: string | RegExp, isNot: boolean): RuleResult {\n const violations: string[] = [];\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n\n for (const c of this.classes) {\n const name = c.name?.text;\n const matches = name && regex.test(name);\n if (isNot && matches) {\n violations.push(`Class ${name} matches pattern ${pattern}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`Class ${name || 'Anonymous'} does not match pattern ${pattern}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkExtendClass(className: string, isNot: boolean): RuleResult {\n const violations: string[] = [];\n for (const c of this.classes) {\n const name = c.name?.text || 'Anonymous';\n let matches = false;\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ExtendsKeyword) {\n for (const type of clause.types) {\n if (ts.isIdentifier(type.expression) && type.expression.text === className) {\n matches = true;\n break;\n }\n }\n }\n }\n }\n if (isNot && matches) {\n violations.push(`Class ${name} extends ${className}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`Class ${name} does not extend ${className}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkImplementInterface(interfaceName: string, isNot: boolean): RuleResult {\n const violations: string[] = [];\n for (const c of this.classes) {\n const name = c.name?.text || 'Anonymous';\n let matches = false;\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ImplementsKeyword) {\n for (const type of clause.types) {\n if (ts.isIdentifier(type.expression) && type.expression.text === interfaceName) {\n matches = true;\n break;\n }\n }\n }\n }\n }\n if (isNot && matches) {\n violations.push(`Class ${name} implements ${interfaceName}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`Class ${name} does not implement ${interfaceName}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkHaveModifier(modifierStr: string, isNot: boolean): RuleResult {\n let targetKind: ts.SyntaxKind;\n switch (modifierStr) {\n case 'export': targetKind = ts.SyntaxKind.ExportKeyword; break;\n case 'default': targetKind = ts.SyntaxKind.DefaultKeyword; break;\n case 'abstract': targetKind = ts.SyntaxKind.AbstractKeyword; break;\n default:\n throw new Error(`Modifier ${modifierStr} is not fully supported.`);\n }\n\n const violations: string[] = [];\n for (const c of this.classes) {\n const name = c.name?.text || 'Anonymous';\n const modifiers = ts.canHaveModifiers(c) ? ts.getModifiers(c) : undefined;\n const matches = modifiers && modifiers.some((m: ts.Modifier) => m.kind === targetKind);\n\n if (isNot && matches) {\n violations.push(`Class ${name} has modifier ${modifierStr}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`Class ${name} does not have modifier ${modifierStr}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n}\n","import * as ts from 'typescript';\nimport { RuleResult } from './types';\n\nexport class LayeredArchitectureBuilder {\n private files: ts.SourceFile[];\n private layers = new Map<string, string>();\n private assertions: Array<(files: ts.SourceFile[]) => string[]> = [];\n\n constructor(files: ts.SourceFile[], public program: ts.Program) {\n this.files = files;\n }\n\n layer(name: string, folderPattern: string): this {\n this.layers.set(name, folderPattern);\n return this;\n }\n\n whereLayer(name: string): LayerAssertionBuilder {\n if (!this.layers.has(name)) {\n throw new Error(`Layer ${name} is not defined`);\n }\n return new LayerAssertionBuilder(this, name);\n }\n\n addAssertion(assertion: (files: ts.SourceFile[]) => string[]) {\n this.assertions.push(assertion);\n }\n\n getFiles(): ts.SourceFile[] {\n return this.files;\n }\n\n getLayerPattern(name: string): string {\n return this.layers.get(name)!;\n }\n\n getFileDependencies(sourceFile: ts.SourceFile): string[] {\n const dependencies: string[] = [];\n const compilerOptions = this.program.getCompilerOptions();\n\n const visit = (node: ts.Node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(moduleSpecifier, sourceFile.fileName, compilerOptions, ts.sys);\n if (resolved.resolvedModule && resolved.resolvedModule.resolvedFileName && !resolved.resolvedModule.isExternalLibraryImport) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(moduleSpecifier, sourceFile.fileName, compilerOptions, ts.sys);\n if (resolved.resolvedModule && resolved.resolvedModule.resolvedFileName && !resolved.resolvedModule.isExternalLibraryImport) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return dependencies;\n }\n\n check(): RuleResult {\n const violations: string[] = [];\n for (const assertion of this.assertions) {\n violations.push(...assertion(this.files));\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n')\n };\n }\n}\n\nexport class LayerAssertionBuilder {\n constructor(private parent: LayeredArchitectureBuilder, private targetLayer: string) {}\n\n shouldNotBeAccessedByAnyLayer(): LayeredArchitectureBuilder {\n this.parent.addAssertion((files) => {\n const violations: string[] = [];\n const targetPattern = this.parent.getLayerPattern(this.targetLayer);\n\n for (const file of files) {\n const filePath = file.fileName;\n if (!filePath.includes(`/${targetPattern}/`) && !filePath.includes(`\\\\${targetPattern}\\\\`)) {\n const dependencies = this.parent.getFileDependencies(file);\n const importsTarget = dependencies.some(dep => dep.includes(`/${targetPattern}/`) || dep.includes(`\\\\${targetPattern}\\\\`));\n if (importsTarget) {\n violations.push(`File ${filePath} accesses layer ${this.targetLayer} but it shouldn't.`);\n }\n }\n }\n return violations;\n });\n return this.parent;\n }\n\n shouldOnlyBeAccessedBy(...allowedLayers: string[]): LayeredArchitectureBuilder {\n this.parent.addAssertion((files) => {\n const violations: string[] = [];\n const targetPattern = this.parent.getLayerPattern(this.targetLayer);\n const allowedPatterns = allowedLayers.map(l => this.parent.getLayerPattern(l));\n\n for (const file of files) {\n const filePath = file.fileName;\n const isInAllowedLayer = allowedPatterns.some(p => filePath.includes(`/${p}/`) || filePath.includes(`\\\\${p}\\\\`));\n \n if (!filePath.includes(`/${targetPattern}/`) && !filePath.includes(`\\\\${targetPattern}\\\\`) && !isInAllowedLayer) {\n const dependencies = this.parent.getFileDependencies(file);\n const importsTarget = dependencies.some(dep => dep.includes(`/${targetPattern}/`) || dep.includes(`\\\\${targetPattern}\\\\`));\n if (importsTarget) {\n violations.push(`File ${filePath} accesses layer ${this.targetLayer} but only ${allowedLayers.join(', ')} are allowed.`);\n }\n }\n }\n return violations;\n });\n return this.parent;\n }\n}\n","import * as ts from 'typescript';\nimport { RuleResult } from './types';\n\nexport interface FunctionQueryOptions {\n inFolder?: string;\n matchNamePattern?: string | RegExp;\n isTopLevel?: boolean;\n}\n\nexport class FunctionLocator {\n public readonly functions: ts.FunctionLikeDeclaration[];\n\n constructor(functions: ts.FunctionLikeDeclaration[], private program: ts.Program, options?: FunctionQueryOptions) {\n let filtered = functions;\n\n if (options?.inFolder) {\n filtered = filtered.filter((f) => {\n const sourceFile = f.getSourceFile();\n return sourceFile.fileName.includes(`/${options.inFolder}/`) || sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`);\n });\n }\n\n if (options?.matchNamePattern) {\n const regex = typeof options.matchNamePattern === 'string' ? new RegExp(options.matchNamePattern) : options.matchNamePattern;\n filtered = filtered.filter((f) => {\n return f.name && ts.isIdentifier(f.name) && regex.test(f.name.text);\n });\n }\n\n if (options?.isTopLevel) {\n filtered = filtered.filter((f) => {\n return ts.isSourceFile(f.parent);\n });\n }\n\n this.functions = filtered;\n }\n\n checkHaveModifier(modifierStr: string, isNot: boolean): RuleResult {\n let targetKind: ts.SyntaxKind;\n switch (modifierStr) {\n case 'export': targetKind = ts.SyntaxKind.ExportKeyword; break;\n case 'async': targetKind = ts.SyntaxKind.AsyncKeyword; break;\n case 'private': targetKind = ts.SyntaxKind.PrivateKeyword; break;\n case 'public': targetKind = ts.SyntaxKind.PublicKeyword; break;\n default:\n throw new Error(`Modifier ${modifierStr} is not fully supported.`);\n }\n\n const violations: string[] = [];\n for (const f of this.functions) {\n const name = f.name && ts.isIdentifier(f.name) ? f.name.text : 'Anonymous Function';\n const modifiers = ts.canHaveModifiers(f) ? ts.getModifiers(f) : undefined;\n const matches = modifiers && modifiers.some((m: ts.Modifier) => m.kind === targetKind);\n\n if (isNot && matches) {\n violations.push(`Function ${name} has modifier ${modifierStr}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`Function ${name} does not have modifier ${modifierStr}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkHaveExplicitReturnType(isNot: boolean): RuleResult {\n const violations: string[] = [];\n for (const f of this.functions) {\n const name = f.name && ts.isIdentifier(f.name) ? f.name.text : 'Anonymous Function';\n const hasType = !!f.type;\n\n if (isNot && hasType) {\n violations.push(`Function ${name} has an explicit return type, but it shouldn't.`);\n } else if (!isNot && !hasType) {\n violations.push(`Function ${name} does not have an explicit return type, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n\n checkMatchNamePattern(pattern: string | RegExp, isNot: boolean): RuleResult {\n const violations: string[] = [];\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n\n for (const f of this.functions) {\n const name = f.name && ts.isIdentifier(f.name) ? f.name.text : undefined;\n const matches = name && regex.test(name);\n \n if (isNot && matches) {\n violations.push(`Function ${name} matches pattern ${pattern}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(`Function ${name || 'Anonymous Function'} does not match pattern ${pattern}, but it should.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n}\n","import * as ts from 'typescript';\nimport { RuleResult } from './types';\n\nexport interface PropertyQueryOptions {\n inFolder?: string;\n matchNamePattern?: string | RegExp;\n}\n\nexport class PropertyLocator {\n public readonly properties: ts.PropertyDeclaration[];\n\n constructor(properties: ts.PropertyDeclaration[], private program: ts.Program, options?: PropertyQueryOptions) {\n let filtered = properties;\n\n if (options?.inFolder) {\n filtered = filtered.filter((p) => {\n const sourceFile = p.getSourceFile();\n return sourceFile.fileName.includes(`/${options.inFolder}/`) || sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`);\n });\n }\n\n if (options?.matchNamePattern) {\n const regex = typeof options.matchNamePattern === 'string' ? new RegExp(options.matchNamePattern) : options.matchNamePattern;\n filtered = filtered.filter((p) => {\n return ts.isIdentifier(p.name) && regex.test(p.name.text);\n });\n }\n\n this.properties = filtered;\n }\n\n checkBeReadonly(isNot: boolean): RuleResult {\n const violations: string[] = [];\n for (const p of this.properties) {\n const name = ts.isIdentifier(p.name) ? p.name.text : 'Anonymous Property';\n const modifiers = ts.canHaveModifiers(p) ? ts.getModifiers(p) : undefined;\n const matches = modifiers && modifiers.some((m: ts.Modifier) => m.kind === ts.SyntaxKind.ReadonlyKeyword);\n\n if (isNot && matches) {\n violations.push(`Property ${name} is readonly, but it shouldn't be.`);\n } else if (!isNot && !matches) {\n violations.push(`Property ${name} is not readonly, but it should be.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n}\n","import * as ts from 'typescript';\nimport { RuleResult } from './types';\n\nexport class SliceLocator {\n private slicePattern: RegExp;\n private sliceIds: Set<string> = new Set();\n private sliceFiles: Map<string, ts.SourceFile[]> = new Map();\n\n constructor(sourceFiles: ts.SourceFile[], private program: ts.Program, pattern: string) {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regexStr = escaped.replace(/\\*/g, '([^/\\\\\\\\]+)');\n this.slicePattern = new RegExp(regexStr);\n\n for (const sf of sourceFiles) {\n const match = sf.fileName.match(this.slicePattern);\n if (match && match[1]) {\n const sliceId = match[1];\n this.sliceIds.add(sliceId);\n if (!this.sliceFiles.has(sliceId)) {\n this.sliceFiles.set(sliceId, []);\n }\n this.sliceFiles.get(sliceId)!.push(sf);\n }\n }\n }\n\n checkBeFreeOfCycles(isNot: boolean): RuleResult {\n const graph: Map<string, Set<string>> = new Map();\n for (const slice of this.sliceIds) {\n graph.set(slice, new Set());\n }\n\n for (const [sliceId, files] of this.sliceFiles.entries()) {\n for (const sf of files) {\n ts.forEachChild(sf, (node) => {\n if (ts.isImportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {\n const importPath = node.moduleSpecifier.text;\n const resolved = ts.resolveModuleName(importPath, sf.fileName, this.program.getCompilerOptions(), ts.sys);\n if (resolved.resolvedModule && resolved.resolvedModule.resolvedFileName) {\n const targetMatch = resolved.resolvedModule.resolvedFileName.match(this.slicePattern);\n if (targetMatch && targetMatch[1]) {\n const targetSlice = targetMatch[1];\n if (targetSlice !== sliceId && this.sliceIds.has(targetSlice)) {\n graph.get(sliceId)!.add(targetSlice);\n }\n }\n }\n }\n });\n }\n }\n\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n const violations: string[] = [];\n\n const dfs = (node: string, path: string[]): boolean => {\n visited.add(node);\n recursionStack.add(node);\n\n for (const neighbor of (graph.get(node) || [])) {\n if (!visited.has(neighbor)) {\n if (dfs(neighbor, [...path, neighbor])) return true;\n } else if (recursionStack.has(neighbor)) {\n violations.push(`Cycle detected between slices: ${path.join(' -> ')} -> ${neighbor}`);\n return true;\n }\n }\n\n recursionStack.delete(node);\n return false;\n };\n\n for (const slice of this.sliceIds) {\n if (!visited.has(slice)) {\n dfs(slice, [slice]);\n }\n }\n\n if (isNot) {\n return {\n pass: violations.length > 0,\n message: () => violations.length > 0 ? '' : 'Expected cycles between slices but found none.'\n };\n } else {\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n')\n };\n }\n }\n}\n","import * as ts from 'typescript';\nimport * as path from 'path';\nimport { FileLocator, FileQueryOptions } from './FileLocator';\nimport { ClassLocator, ClassQueryOptions } from './ClassLocator';\nimport { LayeredArchitectureBuilder } from './LayerLocator';\nimport { FunctionLocator, FunctionQueryOptions } from './FunctionLocator';\nimport { PropertyLocator, PropertyQueryOptions } from './PropertyLocator';\nimport { SliceLocator } from './SliceLocator';\n\nexport class Project {\n private program: ts.Program;\n private typeChecker: ts.TypeChecker;\n\n constructor(options: { tsConfigFilePath?: string } = {}) {\n let compilerOptions: ts.CompilerOptions = {};\n const configPath = options.tsConfigFilePath || ts.findConfigFile(\n process.cwd(),\n ts.sys.fileExists,\n 'tsconfig.json'\n );\n\n if (configPath) {\n const configFile = ts.readConfigFile(configPath, ts.sys.readFile);\n const parsedCommandLine = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n path.dirname(configPath),\n undefined,\n configPath,\n undefined,\n [\n { extension: '.vue', isMixedContent: true, scriptKind: ts.ScriptKind.TS },\n { extension: '.svelte', isMixedContent: true, scriptKind: ts.ScriptKind.TS }\n ]\n );\n compilerOptions = parsedCommandLine.options;\n\n const host = ts.createCompilerHost(compilerOptions);\n const originalGetSourceFile = host.getSourceFile;\n\n let vueCompiler: any;\n try {\n vueCompiler = require('@vue/compiler-sfc');\n } catch (e) {\n // Not a Vue project\n }\n\n host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {\n if (fileName.endsWith('.vue')) {\n const content = ts.sys.readFile(fileName);\n if (content) {\n let scriptContent = '';\n if (vueCompiler) {\n const parsed = vueCompiler.parse(content);\n const script = parsed.descriptor.script;\n const scriptSetup = parsed.descriptor.scriptSetup;\n if (script) scriptContent += script.content + '\\n';\n if (scriptSetup) scriptContent += scriptSetup.content + '\\n';\n } else {\n // Fallback for Svelte or if compiler-sfc is missing (fragile but works for simple cases)\n const match = content.match(/<script[^>]*>(.*?)<\\/script>/s);\n if (match) scriptContent = match[1];\n }\n return ts.createSourceFile(fileName, scriptContent, languageVersion, true, ts.ScriptKind.TS);\n }\n }\n \n if (fileName.endsWith('.svelte')) {\n const content = ts.sys.readFile(fileName);\n if (content) {\n let scriptContent = '';\n const match = content.match(/<script[^>]*>(.*?)<\\/script>/s);\n if (match) scriptContent = match[1];\n return ts.createSourceFile(fileName, scriptContent, languageVersion, true, ts.ScriptKind.TS);\n }\n }\n\n return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);\n };\n\n this.program = ts.createProgram({\n rootNames: parsedCommandLine.fileNames,\n options: compilerOptions,\n host: host\n });\n } else {\n throw new Error(\"Could not find tsconfig.json\");\n }\n\n this.typeChecker = this.program.getTypeChecker();\n }\n\n getFiles(options?: FileQueryOptions) {\n const sourceFiles = this.program.getSourceFiles().filter(\n sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')\n );\n return new FileLocator(sourceFiles, this.program, options);\n }\n\n getClasses(options?: ClassQueryOptions) {\n const sourceFiles = this.program.getSourceFiles().filter(\n sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')\n );\n \n const allClasses: ts.ClassDeclaration[] = [];\n for (const sf of sourceFiles) {\n const visit = (node: ts.Node) => {\n if (ts.isClassDeclaration(node)) {\n allClasses.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return new ClassLocator(allClasses, this.program, options);\n }\n\n layeredArchitecture() {\n const sourceFiles = this.program.getSourceFiles().filter(\n sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')\n );\n return new LayeredArchitectureBuilder(sourceFiles, this.program);\n }\n\n getFunctions(options?: FunctionQueryOptions) {\n const sourceFiles = this.program.getSourceFiles().filter(\n sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')\n );\n \n const allFunctions: ts.FunctionLikeDeclaration[] = [];\n for (const sf of sourceFiles) {\n const visit = (node: ts.Node) => {\n if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isArrowFunction(node)) {\n allFunctions.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return new FunctionLocator(allFunctions, this.program, options);\n }\n\n getProperties(options?: PropertyQueryOptions) {\n const sourceFiles = this.program.getSourceFiles().filter(\n sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')\n );\n \n const allProperties: ts.PropertyDeclaration[] = [];\n for (const sf of sourceFiles) {\n const visit = (node: ts.Node) => {\n if (ts.isPropertyDeclaration(node)) {\n allProperties.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return new PropertyLocator(allProperties, this.program, options);\n }\n\n getSlices(pattern: string) {\n const sourceFiles = this.program.getSourceFiles().filter(\n sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')\n );\n return new SliceLocator(sourceFiles, this.program, pattern);\n }\n}\n\nexport function parseProject(tsConfigFilePath?: string): Project {\n return new Project({ tsConfigFilePath });\n}\n","import { expect } from 'vitest';\nimport { RuleResult } from '../core/types';\nimport { ClassLocator } from '../core/ClassLocator';\nimport { FunctionLocator } from '../core/FunctionLocator';\nimport { PropertyLocator } from '../core/PropertyLocator';\nimport { FileLocator } from '../core/FileLocator';\nimport { SliceLocator } from '../core/SliceLocator';\nimport { LayeredArchitectureBuilder } from '../core/LayerLocator';\n\nexport function setupMatchers() {\n expect.extend({\n toPass(received: RuleResult | LayeredArchitectureBuilder) {\n const result = received instanceof LayeredArchitectureBuilder ? received.check() : received;\n const { pass, message } = result;\n return {\n pass: this.isNot ? !pass : pass,\n message: pass \n ? () => 'Expected rule not to pass' \n : () => message()\n };\n },\n\n toResideInFolder(received: ClassLocator, folder: string) {\n const { pass, message } = received.checkResideInFolder(folder, this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toHaveModifier(received: ClassLocator | FunctionLocator, modifier: string) {\n const { pass, message } = received.checkHaveModifier(modifier, this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n\n\n toExtendClass(received: ClassLocator, className: string) {\n const { pass, message } = received.checkExtendClass(className, this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toImplementInterface(received: ClassLocator, interfaceName: string) {\n const { pass, message } = received.checkImplementInterface(interfaceName, this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toHaveExplicitReturnType(received: FunctionLocator) {\n const { pass, message } = received.checkHaveExplicitReturnType(this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toBeReadonly(received: PropertyLocator) {\n const { pass, message } = received.checkBeReadonly(this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toDependOnFilesInFolder(received: FileLocator, folder: string) {\n const { pass, message } = received.checkDependOnFilesInFolder(folder, this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toBeFreeOfCycles(received: FileLocator | SliceLocator) {\n const { pass, message } = received.checkBeFreeOfCycles(this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n },\n\n toMatchNamePattern(received: FileLocator | ClassLocator | FunctionLocator, pattern: string | RegExp) {\n const { pass, message } = received.checkMatchNamePattern(pattern, this.isNot);\n return {\n pass: this.isNot ? !pass : pass,\n message\n };\n }\n });\n}\n\ndeclare module 'vitest' {\n interface Assertion<T = any> {\n toPass(): void;\n toResideInFolder(folder: string): void;\n toHaveModifier(modifier: 'export' | 'default' | 'abstract' | 'async' | 'private' | 'public'): void;\n\n toExtendClass(className: string): void;\n toImplementInterface(interfaceName: string): void;\n toHaveExplicitReturnType(): void;\n toBeReadonly(): void;\n toDependOnFilesInFolder(folder: string): void;\n toBeFreeOfCycles(): void;\n toMatchNamePattern(pattern: string | RegExp): void;\n }\n}\n"],"mappings":"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"}
|