@archest/vitest 1.0.1 → 1.0.2
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.d.ts +3 -0
- package/dist/index.js +1 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -764
- package/dist/index.mjs.map +1 -1
- package/dist/matchers/index.d.ts +21 -0
- package/dist/matchers/models.d.ts +201 -0
- package/node_modules/@archest/core/dist/classes/locateClasses.d.ts +5 -0
- package/node_modules/@archest/core/dist/classes/types.d.ts +25 -0
- package/node_modules/@archest/core/dist/dto.d.ts +78 -0
- package/node_modules/@archest/core/dist/files/checkDependOnExternalModule.d.ts +3 -0
- package/node_modules/@archest/core/dist/files/getFileDependencies.d.ts +2 -0
- package/node_modules/@archest/core/dist/files/locateFiles.d.ts +4 -0
- package/node_modules/@archest/core/dist/files/types.d.ts +17 -0
- package/node_modules/@archest/core/dist/functions/locateFunctions.d.ts +5 -0
- package/node_modules/@archest/core/dist/functions/types.d.ts +19 -0
- package/node_modules/@archest/core/dist/index.d.ts +43 -0
- package/node_modules/@archest/core/dist/index.js +14 -0
- package/node_modules/@archest/core/dist/index.js.map +1 -0
- package/node_modules/@archest/core/dist/index.mjs +615 -0
- package/node_modules/@archest/core/dist/index.mjs.map +1 -0
- package/node_modules/@archest/core/dist/layers/createLayeredArchitecture.d.ts +3 -0
- package/node_modules/@archest/core/dist/layers/getLayerDependencies.d.ts +2 -0
- package/node_modules/@archest/core/dist/layers/types.d.ts +8 -0
- package/node_modules/@archest/core/dist/project/parseProject.d.ts +55 -0
- package/node_modules/@archest/core/dist/properties/locateProperties.d.ts +5 -0
- package/node_modules/@archest/core/dist/properties/types.d.ts +17 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +1 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +1 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveModifier.d.ts +7 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveNameMatchingFileName.d.ts +3 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckMatchNamePattern.d.ts +1 -0
- package/node_modules/@archest/core/dist/slices/locateSlices.d.ts +3 -0
- package/node_modules/@archest/core/dist/slices/types.d.ts +8 -0
- package/node_modules/@archest/core/package.json +49 -0
- package/node_modules/@archest/core-rust/core-rust.darwin-arm64.node +0 -0
- package/node_modules/@archest/core-rust/core-rust.linux-x64-gnu.node +0 -0
- package/node_modules/@archest/core-rust/core-rust.win32-x64-msvc.node +0 -0
- package/node_modules/@archest/core-rust/index.d.ts +16 -0
- package/node_modules/@archest/core-rust/index.js +316 -0
- package/node_modules/@archest/core-rust/package.json +34 -0
- package/package.json +12 -1
- package/dist/src/core/classes/locateClasses.d.ts +0 -3
- package/dist/src/core/classes/types.d.ts +0 -14
- package/dist/src/core/files/getFileDependencies.d.ts +0 -2
- package/dist/src/core/files/locateFiles.d.ts +0 -3
- package/dist/src/core/files/types.d.ts +0 -10
- package/dist/src/core/functions/locateFunctions.d.ts +0 -3
- package/dist/src/core/functions/types.d.ts +0 -11
- package/dist/src/core/layers/createLayeredArchitecture.d.ts +0 -3
- package/dist/src/core/layers/getLayerDependencies.d.ts +0 -2
- package/dist/src/core/layers/types.d.ts +0 -8
- package/dist/src/core/project/parseProject.d.ts +0 -22
- package/dist/src/core/properties/locateProperties.d.ts +0 -3
- package/dist/src/core/properties/types.d.ts +0 -10
- package/dist/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +0 -1
- package/dist/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +0 -1
- package/dist/src/core/shared/sharedCheckHaveModifier.d.ts +0 -2
- package/dist/src/core/shared/sharedCheckHaveNameMatchingFileName.d.ts +0 -2
- package/dist/src/core/shared/sharedCheckMatchNamePattern.d.ts +0 -1
- package/dist/src/core/slices/locateSlices.d.ts +0 -3
- package/dist/src/core/slices/types.d.ts +0 -8
- package/dist/src/index.d.ts +0 -35
- package/dist/src/matchers/index.d.ts +0 -20
- package/src/core/classes/classCheckExtendClass.test.ts +0 -30
- package/src/core/classes/classCheckExtendClass.ts +0 -41
- package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
- package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.ts +0 -35
- package/src/core/classes/classCheckHaveModifier.test.ts +0 -30
- package/src/core/classes/classCheckHaveModifier.ts +0 -17
- package/src/core/classes/classCheckHaveNameMatchingFileName.test.ts +0 -30
- package/src/core/classes/classCheckHaveNameMatchingFileName.ts +0 -15
- package/src/core/classes/classCheckImplementInterface.test.ts +0 -30
- package/src/core/classes/classCheckImplementInterface.ts +0 -43
- package/src/core/classes/classCheckMatchNamePattern.test.ts +0 -8
- package/src/core/classes/classCheckMatchNamePattern.ts +0 -17
- package/src/core/classes/classCheckResideInFolder.test.ts +0 -8
- package/src/core/classes/classCheckResideInFolder.ts +0 -31
- package/src/core/classes/locateClasses.test.ts +0 -13
- package/src/core/classes/locateClasses.ts +0 -127
- package/src/core/classes/types.ts +0 -16
- package/src/core/files/checkDependOnFilesInFolder.test.ts +0 -7
- package/src/core/files/checkDependOnFilesInFolder.ts +0 -36
- package/src/core/files/fileCheckBeFreeOfCycles.test.ts +0 -7
- package/src/core/files/fileCheckBeFreeOfCycles.ts +0 -72
- package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
- package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.ts +0 -35
- package/src/core/files/fileCheckHaveMaxExportedFunctions.test.ts +0 -32
- package/src/core/files/fileCheckHaveMaxExportedFunctions.ts +0 -45
- package/src/core/files/fileCheckHaveMinMaintainabilityIndex.test.ts +0 -8
- package/src/core/files/fileCheckHaveMinMaintainabilityIndex.ts +0 -19
- package/src/core/files/fileCheckMatchNamePattern.test.ts +0 -30
- package/src/core/files/fileCheckMatchNamePattern.ts +0 -17
- package/src/core/files/getFileDependencies.ts +0 -43
- package/src/core/files/locateFiles.test.ts +0 -30
- package/src/core/files/locateFiles.ts +0 -31
- package/src/core/files/types.ts +0 -12
- package/src/core/functions/functionCheckHaveExplicitReturnType.test.ts +0 -30
- package/src/core/functions/functionCheckHaveExplicitReturnType.ts +0 -29
- package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
- package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.ts +0 -20
- package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.test.ts +0 -8
- package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.ts +0 -20
- package/src/core/functions/functionCheckHaveModifier.test.ts +0 -30
- package/src/core/functions/functionCheckHaveModifier.ts +0 -18
- package/src/core/functions/functionCheckHaveNameMatchingFileName.test.ts +0 -30
- package/src/core/functions/functionCheckHaveNameMatchingFileName.ts +0 -16
- package/src/core/functions/functionCheckMatchNamePattern.test.ts +0 -30
- package/src/core/functions/functionCheckMatchNamePattern.ts +0 -18
- package/src/core/functions/locateFunctions.test.ts +0 -16
- package/src/core/functions/locateFunctions.ts +0 -47
- package/src/core/functions/types.ts +0 -13
- package/src/core/layers/checkLayeredArchitecture.test.ts +0 -23
- package/src/core/layers/checkLayeredArchitecture.ts +0 -15
- package/src/core/layers/createLayeredArchitecture.test.ts +0 -13
- package/src/core/layers/createLayeredArchitecture.ts +0 -15
- package/src/core/layers/getLayerDependencies.ts +0 -45
- package/src/core/layers/layer.test.ts +0 -12
- package/src/core/layers/layer.ts +0 -10
- package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.test.ts +0 -14
- package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.ts +0 -40
- package/src/core/layers/layerShouldOnlyBeAccessedBy.test.ts +0 -15
- package/src/core/layers/layerShouldOnlyBeAccessedBy.ts +0 -48
- package/src/core/layers/types.ts +0 -9
- package/src/core/metrics/calculateCyclomaticComplexity.test.ts +0 -23
- package/src/core/metrics/calculateCyclomaticComplexity.ts +0 -36
- package/src/core/metrics/calculateMaintainabilityIndex.test.ts +0 -38
- package/src/core/metrics/calculateMaintainabilityIndex.ts +0 -47
- package/src/core/project/parseProject.test.ts +0 -19
- package/src/core/project/parseProject.ts +0 -216
- package/src/core/properties/locateProperties.test.ts +0 -19
- package/src/core/properties/locateProperties.ts +0 -41
- package/src/core/properties/propertyCheckBeReadonly.test.ts +0 -32
- package/src/core/properties/propertyCheckBeReadonly.ts +0 -27
- package/src/core/properties/types.ts +0 -12
- package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.test.ts +0 -30
- package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.ts +0 -23
- package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.test.ts +0 -30
- package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.ts +0 -23
- package/src/core/shared/sharedCheckHaveModifier.test.ts +0 -31
- package/src/core/shared/sharedCheckHaveModifier.ts +0 -51
- package/src/core/shared/sharedCheckHaveNameMatchingFileName.test.ts +0 -17
- package/src/core/shared/sharedCheckHaveNameMatchingFileName.ts +0 -36
- package/src/core/shared/sharedCheckMatchNamePattern.test.ts +0 -29
- package/src/core/shared/sharedCheckMatchNamePattern.ts +0 -22
- package/src/core/slices/locateSlices.test.ts +0 -22
- package/src/core/slices/locateSlices.ts +0 -35
- package/src/core/slices/sliceCheckBeFreeOfCycles.test.ts +0 -26
- package/src/core/slices/sliceCheckBeFreeOfCycles.ts +0 -91
- package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.test.ts +0 -27
- package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.ts +0 -110
- package/src/core/slices/types.ts +0 -9
- package/src/core/testUtils.ts +0 -61
- package/src/core/types.ts +0 -19
- package/src/core/utils/ruleBuilder.test.ts +0 -24
- package/src/core/utils/ruleBuilder.ts +0 -28
- package/src/index.ts +0 -35
- package/src/matchers/index.ts +0 -331
- package/test/architecture.test.ts +0 -152
- package/tsconfig.json +0 -18
- package/vite.config.ts +0 -18
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckExtendClass.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveModifier.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveNameMatchingFileName.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckImplementInterface.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckMatchNamePattern.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckResideInFolder.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/checkDependOnFilesInFolder.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckBeFreeOfCycles.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMaxExportedFunctions.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMinMaintainabilityIndex.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckMatchNamePattern.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveExplicitReturnType.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveMinMaintainabilityIndex.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveModifier.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveNameMatchingFileName.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckMatchNamePattern.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/checkLayeredArchitecture.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layer.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layerShouldNotBeAccessedByAnyLayer.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layerShouldOnlyBeAccessedBy.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/metrics/calculateCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/metrics/calculateMaintainabilityIndex.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/properties/propertyCheckBeReadonly.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/slices/sliceCheckBeFreeOfCycles.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/slices/sliceCheckHaveMaxDistanceFromMainSequence.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/types.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/utils/ruleBuilder.d.ts +0 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { ClassData, ClassQueryOptions, FileData, FileQueryOptions, FunctionData, FunctionQueryOptions, ProjectData, PropertyData, PropertyQueryOptions, } from '@archest/core';
|
|
2
|
+
export { type ParseProjectOptions, parseProject, } from '@archest/core';
|
|
3
|
+
export { type ArchestMatchers, setupMatchers } from './matchers';
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(
|
|
2
|
-
`)}}function p(e){let n=1,r=e=>{switch(e.kind){case t.SyntaxKind.IfStatement:case t.SyntaxKind.ForStatement:case t.SyntaxKind.ForInStatement:case t.SyntaxKind.ForOfStatement:case t.SyntaxKind.WhileStatement:case t.SyntaxKind.DoStatement:case t.SyntaxKind.CaseClause:case t.SyntaxKind.CatchClause:case t.SyntaxKind.ConditionalExpression:n++;break;case t.SyntaxKind.BinaryExpression:{let r=e;(r.operatorToken.kind===t.SyntaxKind.AmpersandAmpersandToken||r.operatorToken.kind===t.SyntaxKind.BarBarToken||r.operatorToken.kind===t.SyntaxKind.QuestionQuestionToken)&&n++;break}}t.forEachChild(e,r)};return t.forEachChild(e,r),n}function m(e,t,n){let r=[];for(let i of e){let{passes:e,failMessage:a,failNotMessage:o}=n(i);t&&e?o&&r.push(o):!t&&!e&&a&&r.push(a)}return{pass:r.length===0,message:()=>r.join(`
|
|
3
|
-
`)}}function h(e,t,n,r,i,a){return m(e,a,e=>{let a=t(e),o=n(e),s=o>i,c=`${r} ${a||`Anonymous`}`;return{passes:!s,failMessage:`${c} has a total cyclomatic complexity of ${o}, which exceeds the maximum of ${i}.`,failNotMessage:`${c} has a total cyclomatic complexity of ${o}, which exceeds the maximum of ${i}, but it shouldn't.`}})}function g(e,n,r){return h(e.classes,e=>e.name?.text,e=>{let n=0,r=e=>{(t.isMethodDeclaration(e)||t.isConstructorDeclaration(e)||t.isGetAccessor(e)||t.isSetAccessor(e))&&(n+=p(e)),t.forEachChild(e,r)};return r(e),n},`Class`,n,r)}function _(e,n,r,i,a){let o;switch(i){case`export`:o=t.SyntaxKind.ExportKeyword;break;case`default`:o=t.SyntaxKind.DefaultKeyword;break;case`abstract`:o=t.SyntaxKind.AbstractKeyword;break;case`async`:o=t.SyntaxKind.AsyncKeyword;break;case`public`:o=t.SyntaxKind.PublicKeyword;break;case`private`:o=t.SyntaxKind.PrivateKeyword;break;default:throw Error(`Modifier ${i} is not fully supported.`)}return m(e,a,e=>{let a=n(e),s=t.canHaveModifiers(e)?t.getModifiers(e):void 0,c=s?s.some(e=>e.kind===o):!1,l=`${r} ${a||`Anonymous`}`;return{passes:c,failMessage:`${l} does not have modifier ${i}, but it should.`,failNotMessage:`${l} has modifier ${i}, but it shouldn't.`}})}function v(e,t,n){return _(e.classes,e=>e.name?.text,`Class`,t,n)}function y(e,r,i,a){return m(e,a,e=>{let a=r(e),o=e.getSourceFile?e.getSourceFile():e.parent?t.getSourceFileOfNode(e):void 0;if(!o)return{passes:!0,failMessage:``,failNotMessage:``};let s=n.basename(o.fileName,n.extname(o.fileName)),c=a===s,l=`${i} ${a||`Anonymous`}`;return{passes:c,failMessage:`${l} does not have a name matching its filename ${s}, but it should.`,failNotMessage:`${l} has a name matching its filename ${s}, but it shouldn't.`}})}function b(e,t){return y(e.classes,e=>e.name?.text,`Class`,t)}function x(e,n,r){let i=[];for(let a of e.classes){let e=a.name?.text||`Anonymous`,o=!1;if(a.heritageClauses){for(let e of a.heritageClauses)if(e.token===t.SyntaxKind.ImplementsKeyword){for(let r of e.types)if(t.isIdentifier(r.expression)&&r.expression.text===n){o=!0;break}}}r&&o?i.push(`Class ${e} implements ${n}, but it shouldn't.`):!r&&!o&&i.push(`Class ${e} does not implement ${n}, but it should.`)}return{pass:i.length===0,message:()=>i.join(`
|
|
4
|
-
`)}}function S(e,t,n,r,i){let a=typeof r==`string`?new RegExp(r):r;return m(e,i,e=>{let i=t(e),o=i?a.test(i):!1,s=`${n} ${i||`Anonymous`}`;return{passes:o,failMessage:`${s} does not match pattern ${r}, but it should.`,failNotMessage:`${s} matches pattern ${r}, but it shouldn't.`}})}function C(e,t,n){return S(e.classes,e=>e.name?.text,`Class`,t,n)}function w(e,t,n){let r=[];for(let i of e.classes){let e=i.name?.text||`Anonymous Class`,a=i.getSourceFile(),o=a.fileName.includes(`/${t}/`)||a.fileName.includes(`\\${t}\\`);n&&o?r.push(`Class ${e} resides in ${t}, but it shouldn't.`):!n&&!o&&r.push(`Class ${e} does not reside in ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
5
|
-
`)}}function T(e,n,r){let i=e;if(r?.inFolder&&(i=i.filter(e=>{let n=e.getSourceFile?e.getSourceFile():e.parent?t.getSourceFileOfNode(e):void 0;return n?n.fileName.includes(`/${r.inFolder}/`)||n.fileName.includes(`\\${r.inFolder}\\`):!1})),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=>(t.canHaveModifiers(n)?t.getModifiers(n):void 0)?.some(t=>t.kind===e))}return{type:`ClassLocator`,classes:i,program:n}}function E(e,n){let r=[],i=n.getCompilerOptions(),a=n=>{if(t.isImportDeclaration(n)){let a=n.moduleSpecifier.text,o=t.resolveModuleName(a,e.fileName,i,t.sys);o.resolvedModule?.resolvedFileName&&(o.resolvedModule.isExternalLibraryImport||r.push(o.resolvedModule.resolvedFileName))}else if(t.isExportDeclaration(n)&&n.moduleSpecifier){let a=n.moduleSpecifier.text,o=t.resolveModuleName(a,e.fileName,i,t.sys);o.resolvedModule?.resolvedFileName&&(o.resolvedModule.isExternalLibraryImport||r.push(o.resolvedModule.resolvedFileName))}t.forEachChild(n,a)};return a(e),r}function D(e,t,n){let r=[];for(let i of e.files){let a=E(i,e.program).some(e=>e.includes(`/${t}/`)||e.includes(`\\${t}\\`));n&&a?r.push(`File ${i.fileName} depends on files in ${t}, but it shouldn't.`):!n&&!a&&r.push(`File ${i.fileName} does not depend on files in ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
6
|
-
`)}}function O(e,t){let n=[],r=new Set(e.files.map(e=>e.fileName)),i=new Map;for(let t of e.files){let n=t.fileName,a=E(t,e.program).filter(e=>r.has(e));i.set(n,a)}let a=new Set,o=new Set,s=[],c=(e,t)=>{if(o.has(e)){let n=t.indexOf(e),r=[...t.slice(n),e].join(`->`);return s.some(e=>e.join(`->`)===r)||s.push([...t.slice(n),e]),!0}if(a.has(e))return!1;a.add(e),o.add(e),t.push(e);let n=i.get(e)||[];for(let e of n)c(e,t);return o.delete(e),t.pop(),!1};for(let e of i.keys())a.has(e)||c(e,[]);if(t&&s.length===0)n.push(`Expected cyclic dependencies, but found none.`);else if(!t&&s.length>0)for(let e of s)n.push(`Cycle detected: ${e.join(` -> `)}`);return{pass:n.length===0,message:()=>n.join(`
|
|
7
|
-
`)}}function k(e,n,r){return h(e.files,e=>e.fileName,e=>{let n=0,r=e=>{(t.isFunctionDeclaration(e)||t.isMethodDeclaration(e)||t.isArrowFunction(e)||t.isFunctionExpression(e))&&(n+=p(e)),t.forEachChild(e,r)};return r(e),n},`File`,n,r)}function A(e,n,r){let i=[];for(let a of e.files){let e=0;t.forEachChild(a,n=>{t.isFunctionDeclaration(n)&&(t.canHaveModifiers(n)?t.getModifiers(n):void 0)?.some(e=>e.kind===t.SyntaxKind.ExportKeyword)&&e++});let o=e>n;r&&o?i.push(`File ${a.fileName} has ${e} exported functions, which exceeds the maximum of ${n}, but it shouldn't.`):!r&&o&&i.push(`File ${a.fileName} has ${e} exported functions, which exceeds the maximum of ${n}.`)}return{pass:r?i.length>0:i.length===0,message:()=>i.join(`
|
|
8
|
-
`)||(r?`Expected some files to exceed maximum exported functions, but none did.`:``)}}function j(e){let n=0,r=0,i=new Set,a=new Set,o=1,s=e.getSourceFile();if(s){let t=s.getLineAndCharacterOfPosition(e.getStart());o=s.getLineAndCharacterOfPosition(e.getEnd()).line-t.line+1}let c=e=>{t.isBinaryExpression(e)||t.isPrefixUnaryExpression(e)||t.isPostfixUnaryExpression(e)?(n++,i.add(e.kind)):(t.isIdentifier(e)||t.isLiteralExpression(e))&&(r++,a.add(e.getText(s))),t.forEachChild(e,c)};c(e);let l=n+r,u=i.size+a.size,d=u===0?0:l*Math.log2(u),f=p(e);return Math.max(0,(171-5.2*Math.log(d||1)-.23*f-16.2*Math.log(o))*100/171)}function M(e,t,n,r,i,a){return m(e,a,e=>{let a=t(e),o=n(e),s=o<i,c=`${r} ${a||`Anonymous`}`;return{passes:!s,failMessage:`${c} has a maintainability index of ${o.toFixed(2)}, which falls below the minimum of ${i}.`,failNotMessage:`${c} has a maintainability index of ${o.toFixed(2)}, which falls below the minimum of ${i}, but it shouldn't.`}})}function N(e,t,n){return M(e.files,e=>e.fileName,j,`File`,t,n)}function P(e,t,n){return S(e.files,e=>e.fileName,`File`,t,n)}function F(e,t,n){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))}return{type:`FileLocator`,files:r,program:t}}function I(e,n){let r=[];for(let i of e.functions){let e=i.name&&t.isIdentifier(i.name)?i.name.text:`Anonymous Function`,a=!!i.type;n&&a?r.push(`Function ${e} has an explicit return type, but it shouldn't.`):!n&&!a&&r.push(`Function ${e} does not have an explicit return type, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
9
|
-
`)}}function L(e,n,r){return h(e.functions,e=>e.name&&t.isIdentifier(e.name)?e.name.text:void 0,p,`Function`,n,r)}function R(e,n,r){return M(e.functions,e=>e.name&&t.isIdentifier(e.name)?e.name.text:void 0,j,`Function`,n,r)}function z(e,n,r){return _(e.functions,e=>e.name&&t.isIdentifier(e.name)?e.name.text:void 0,`Function`,n,r)}function B(e,n){return y(e.functions,e=>e.name&&t.isIdentifier(e.name)?e.name.text:void 0,`Function`,n)}function V(e,n,r){return S(e.functions,e=>e.name&&t.isIdentifier(e.name)?e.name.text:void 0,`Function`,n,r)}function H(e,n,r){let i=e;if(r?.inFolder&&(i=i.filter(e=>{let n=e.getSourceFile?e.getSourceFile():e.parent?t.getSourceFileOfNode(e):void 0;return n?n.fileName.includes(`/${r.inFolder}/`)||n.fileName.includes(`\\${r.inFolder}\\`):!1})),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))}return r?.isTopLevel&&(i=i.filter(e=>t.isSourceFile(e.parent))),{type:`FunctionLocator`,functions:i,program:n}}function U(e){let t=[];for(let n of e.assertions)t.push(...n(e.files));return{pass:t.length===0,message:()=>t.join(`
|
|
10
|
-
`)}}function W(e,t){return{type:`LayeredArchitecture`,files:e,layers:new Map,assertions:[],program:t}}function G(e,t,n){return e.layers.set(t,n),e}function K(e,n){let r=[],i=n.getCompilerOptions(),a=n=>{if(t.isImportDeclaration(n)){let a=n.moduleSpecifier.text,o=t.resolveModuleName(a,e.fileName,i,t.sys);o.resolvedModule?.resolvedFileName&&!o.resolvedModule.isExternalLibraryImport&&r.push(o.resolvedModule.resolvedFileName)}else if(t.isExportDeclaration(n)&&n.moduleSpecifier){let a=n.moduleSpecifier.text,o=t.resolveModuleName(a,e.fileName,i,t.sys);o.resolvedModule?.resolvedFileName&&!o.resolvedModule.isExternalLibraryImport&&r.push(o.resolvedModule.resolvedFileName)}t.forEachChild(n,a)};return a(e),r}function q(e,t){if(!e.layers.has(t))throw Error(`Layer ${t} is not defined`);return e.assertions.push(n=>{let r=[],i=e.layers.get(t);for(let a of n){let n=a.fileName;!n.includes(`/${i}/`)&&!n.includes(`\\${i}\\`)&&K(a,e.program).some(e=>e.includes(`/${i}/`)||e.includes(`\\${i}\\`))&&r.push(`File ${n} accesses layer ${t} but it shouldn't.`)}return r}),e}function J(e,t,n){if(!e.layers.has(t))throw Error(`Layer ${t} is not defined`);return e.assertions.push(r=>{let i=[],a=e.layers.get(t),o=n.map(t=>e.layers.get(t));for(let s of r){let r=s.fileName,c=o.some(e=>r.includes(`/${e}/`)||r.includes(`\\${e}\\`));!r.includes(`/${a}/`)&&!r.includes(`\\${a}\\`)&&!c&&K(s,e.program).some(e=>e.includes(`/${a}/`)||e.includes(`\\${a}\\`))&&i.push(`File ${r} accesses layer ${t} but only ${n.join(`, `)} are allowed.`)}return i}),e}function Y(e,n,r){let i=e;if(r?.inFolder&&(i=i.filter(e=>{let n=e.getSourceFile?e.getSourceFile():e.parent?t.getSourceFileOfNode(e):void 0;return n?n.fileName.includes(`/${r.inFolder}/`)||n.fileName.includes(`\\${r.inFolder}\\`):!1})),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))}return{type:`PropertyLocator`,properties:i,program:n}}function X(e,t,n){let r=n.replace(/[.+?^${}()|[\]\\]/g,`\\$&`).replace(/\*/g,`([^/\\\\]+)`),i=new RegExp(r),a=new Set,o=new Map;for(let t of e){let e=t.fileName.match(i);if(e?.[1]){let n=e[1];a.add(n),o.has(n)||o.set(n,[]),o.get(n)?.push(t)}}return{type:`SliceLocator`,slicePattern:i,sliceIds:a,sliceFiles:o,program:t}}function ee(e={}){let r={},i=e.tsConfigFilePath||t.findConfigFile(process.cwd(),t.sys.fileExists,`tsconfig.json`),a;if(i){let e=t.readConfigFile(i,t.sys.readFile),o=t.parseJsonConfigFileContent(e.config,t.sys,(0,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=o.options;let s=t.createCompilerHost(r),c=s.getSourceFile,l;try{l=require(`@vue/compiler-sfc`)}catch{}s.getSourceFile=(e,n,r,i)=>{if(e.endsWith(`.vue`)){let r=t.sys.readFile(e);if(r){let i=``;if(l){let e=l.parse(r),t=e.descriptor.script,n=e.descriptor.scriptSetup;t&&(i+=`${t.content}\n`),n&&(i+=`${n.content}\n`)}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 c(e,n,r,i)},a=t.createProgram({rootNames:o.fileNames,options:r,host:s}),a.getTypeChecker()}else throw Error(`Could not find tsconfig.json`);let o=()=>a.getSourceFiles().filter(e=>!e.isDeclarationFile&&!e.fileName.includes(`node_modules`));return{getFiles:e=>F(o(),a,e),getClasses:e=>{let n=[];for(let e of o()){let r=e=>{t.isClassDeclaration(e)&&n.push(e),t.forEachChild(e,r)};r(e)}return T(n,a,e)},layeredArchitecture:()=>{let e=W(o(),a),t={layer:(n,r)=>(e=G(e,n,r),t),whereLayer:n=>({shouldNotBeAccessedByAnyLayer:()=>(e=q(e,n),t),shouldOnlyBeAccessedBy:(...r)=>(e=J(e,n,r),t)}),check:()=>U(e),get data(){return e}};return t},getFunctions:e=>{let n=[];for(let e of o()){let r=e=>{(t.isFunctionDeclaration(e)||t.isMethodDeclaration(e)||t.isArrowFunction(e))&&n.push(e),t.forEachChild(e,r)};r(e)}return H(n,a,e)},getProperties:e=>{let n=[];for(let e of o()){let r=e=>{t.isPropertyDeclaration(e)&&n.push(e),t.forEachChild(e,r)};r(e)}return Y(n,a,e)},getSlices:e=>X(o(),a,e)}}function Z(e,n){let r=[];for(let i of e.properties){let e=t.isIdentifier(i.name)?i.name.text:`Anonymous Property`,a=(t.canHaveModifiers(i)?t.getModifiers(i):void 0)?.some(e=>e.kind===t.SyntaxKind.ReadonlyKeyword);n&&a?r.push(`Property ${e} is readonly, but it shouldn't be.`):!n&&!a&&r.push(`Property ${e} is not readonly, but it should be.`)}return{pass:r.length===0,message:()=>r.join(`
|
|
11
|
-
`)}}function Q(e,n){let r=new Map;for(let t of e.sliceIds)r.set(t,new Set);for(let[n,i]of e.sliceFiles.entries())for(let a of i)t.forEachChild(a,i=>{if(t.isImportDeclaration(i)&&i.moduleSpecifier&&t.isStringLiteral(i.moduleSpecifier)){let o=i.moduleSpecifier.text,s=t.resolveModuleName(o,a.fileName,e.program.getCompilerOptions(),t.sys);if(s.resolvedModule?.resolvedFileName){let t=s.resolvedModule.resolvedFileName.match(e.slicePattern);if(t?.[1]){let i=t[1];i!==n&&e.sliceIds.has(i)&&r.get(n)?.add(i)}}}});let i=new Set,a=new Set,o=[],s=(e,t)=>{i.add(e),a.add(e);for(let n of r.get(e)||[])if(!i.has(n)){if(s(n,[...t,n]))return!0}else if(a.has(n))return o.push(`Cycle detected between slices: ${t.join(` -> `)} -> ${n}`),!0;return a.delete(e),!1};for(let t of e.sliceIds)i.has(t)||s(t,[t]);return n?{pass:o.length>0,message:()=>o.length>0?``:`Expected cycles between slices but found none.`}:{pass:o.length===0,message:()=>o.join(`
|
|
12
|
-
`)}}function $(e,n,r){let i=[],a=new Map,o=new Map;for(let t of e.sliceIds)a.set(t,new Set),o.set(t,new Set);for(let[n,r]of e.sliceFiles.entries())for(let i of r)t.forEachChild(i,r=>{if(t.isImportDeclaration(r)&&r.moduleSpecifier&&t.isStringLiteral(r.moduleSpecifier)){let s=r.moduleSpecifier.text,c=t.resolveModuleName(s,i.fileName,e.program.getCompilerOptions(),t.sys);if(c.resolvedModule?.resolvedFileName){let t=c.resolvedModule.resolvedFileName.match(e.slicePattern);if(t?.[1]){let r=t[1];r!==n&&e.sliceIds.has(r)&&(a.get(n)?.add(r),o.get(r)?.add(n))}}}});for(let s of e.sliceIds){let c=a.get(s)?.size,l=o.get(s)?.size,u=e.sliceFiles.get(s),d=0,f=0;for(let e of u){let n=e=>{t.isClassDeclaration(e)?(f++,(t.canHaveModifiers(e)?t.getModifiers(e):void 0)?.some(e=>e.kind===t.SyntaxKind.AbstractKeyword)&&d++):t.isInterfaceDeclaration(e)&&(f++,d++),t.forEachChild(e,n)};n(e)}let p=c+l===0?0:c/(l+c),m=f===0?0:d/f,h=Math.abs(m+p-1),g=h>n;r&&g?i.push(`Slice ${s} has a Distance from the Main Sequence of ${h.toFixed(2)}, which exceeds the maximum of ${n}, but it shouldn't.`):!r&&g&&i.push(`Slice ${s} has a Distance from the Main Sequence of ${h.toFixed(2)}, which exceeds the maximum of ${n}.`)}return{pass:r?i.length>0:i.length===0,message:()=>i.join(`
|
|
13
|
-
`)||(r?`Expected some slices to exceed maximum distance from main sequence, but none did.`:``)}}function te(){r.expect.extend({toPass(e){let t;t=e?.data&&e.data.type===`LayeredArchitecture`?U(e.data):e;let{pass:n,message:r}=t;return{pass:this.isNot?!n:n,message:n?()=>`Expected rule not to pass`:()=>r()}},toResideInFolder(e,t){let n;if(e.type===`ClassLocator`)n=w(e,t,this.isNot);else throw Error(`toResideInFolder matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveModifier(e,t){let n;if(e.type===`ClassLocator`)n=v(e,t,this.isNot);else if(e.type===`FunctionLocator`)n=z(e,t,this.isNot);else throw Error(`toHaveModifier matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toExtendClass(e,t){let n;if(e.type===`ClassLocator`)n=f(e,t,this.isNot);else throw Error(`toExtendClass matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toImplementInterface(e,t){let n;if(e.type===`ClassLocator`)n=x(e,t,this.isNot);else throw Error(`toImplementInterface matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveExplicitReturnType(e){let t;if(e.type===`FunctionLocator`)t=I(e,this.isNot);else throw Error(`toHaveExplicitReturnType matcher does not support ${e.type}`);return{pass:this.isNot?!t.pass:t.pass,message:t.message}},toBeReadonly(e){let t;if(e.type===`PropertyLocator`)t=Z(e,this.isNot);else throw Error(`toBeReadonly matcher does not support ${e.type}`);return{pass:this.isNot?!t.pass:t.pass,message:t.message}},toDependOnFilesInFolder(e,t){let n;if(e.type===`FileLocator`)n=D(e,t,this.isNot);else throw Error(`toDependOnFilesInFolder matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toBeFreeOfCycles(e){let t;if(e.type===`FileLocator`)t=O(e,this.isNot);else if(e.type===`SliceLocator`)t=Q(e,this.isNot);else throw Error(`toBeFreeOfCycles matcher does not support ${e.type}`);return{pass:this.isNot?!t.pass:t.pass,message:t.message}},toMatchNamePattern(e,t){let n;if(e.type===`FileLocator`)n=P(e,t,this.isNot);else if(e.type===`ClassLocator`)n=C(e,t,this.isNot);else if(e.type===`FunctionLocator`)n=V(e,t,this.isNot);else throw Error(`toMatchNamePattern matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveMaxCyclomaticComplexity(e,t){let n;if(e.type===`FileLocator`)n=k(e,t,this.isNot);else if(e.type===`ClassLocator`)n=g(e,t,this.isNot);else if(e.type===`FunctionLocator`)n=L(e,t,this.isNot);else throw Error(`toHaveMaxCyclomaticComplexity matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveMinMaintainabilityIndex(e,t){let n;if(e.type===`FileLocator`)n=N(e,t,this.isNot);else if(e.type===`FunctionLocator`)n=R(e,t,this.isNot);else throw Error(`toHaveMinMaintainabilityIndex matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveMaxDistanceFromMainSequence(e,t){let n;if(e.type===`SliceLocator`)n=$(e,t,this.isNot);else throw Error(`toHaveMaxDistanceFromMainSequence matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveNameMatchingFileName(e){let t;if(e.type===`FunctionLocator`)t=B(e,this.isNot);else if(e.type===`ClassLocator`)t=b(e,this.isNot);else throw Error(`toHaveNameMatchingFileName matcher does not support ${e.type}`);return{pass:this.isNot?!t.pass:t.pass,message:t.message}},toHaveMaxExportedFunctions(e,t){let n;if(e.type===`FileLocator`)n=A(e,t,this.isNot);else throw Error(`toHaveMaxExportedFunctions matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}}})}e.checkDependOnFilesInFolder=D,e.checkLayeredArchitecture=U,e.classCheckExtendClass=f,e.classCheckHaveMaxCyclomaticComplexity=g,e.classCheckHaveModifier=v,e.classCheckHaveNameMatchingFileName=b,e.classCheckImplementInterface=x,e.classCheckMatchNamePattern=C,e.classCheckResideInFolder=w,e.createLayeredArchitecture=W,e.fileCheckBeFreeOfCycles=O,e.fileCheckHaveMaxCyclomaticComplexity=k,e.fileCheckHaveMaxExportedFunctions=A,e.fileCheckHaveMinMaintainabilityIndex=N,e.fileCheckMatchNamePattern=P,e.functionCheckHaveExplicitReturnType=I,e.functionCheckHaveMaxCyclomaticComplexity=L,e.functionCheckHaveMinMaintainabilityIndex=R,e.functionCheckHaveModifier=z,e.functionCheckHaveNameMatchingFileName=B,e.functionCheckMatchNamePattern=V,e.layer=G,e.layerShouldNotBeAccessedByAnyLayer=q,e.layerShouldOnlyBeAccessedBy=J,e.locateClasses=T,e.locateFiles=F,e.locateFunctions=H,e.locateProperties=Y,e.locateSlices=X,e.parseProject=ee,e.propertyCheckBeReadonly=Z,e.setupMatchers=te,e.sliceCheckBeFreeOfCycles=Q,e.sliceCheckHaveMaxDistanceFromMainSequence=$});
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@archest/core"),require("vitest")):typeof define==`function`&&define.amd?define([`exports`,`@archest/core`,`vitest`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.VitestArch={},e._archest_core,e.vitest))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function r(){n.expect.extend({toPass(e){let n;n=e?.data&&e.data.type===`LayeredArchitecture`?(0,t.checkLayeredArchitecture)(e.data):e;let{pass:r,message:i}=n;return{pass:this.isNot?!r:r,message:r?()=>`Expected rule not to pass`:()=>i()}},toResideInFolder(e,n){let r;if(e.type===`ClassLocator`)r=(0,t.classCheckResideInFolder)(e,n,this.isNot);else throw Error(`toResideInFolder matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toHaveModifier(e,n){let r;if(e.type===`ClassLocator`)r=(0,t.classCheckHaveModifier)(e,n,this.isNot);else if(e.type===`FunctionLocator`)r=(0,t.functionCheckHaveModifier)(e,n,this.isNot);else throw Error(`toHaveModifier matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toExtendClass(e,n){let r;if(e.type===`ClassLocator`)r=(0,t.classCheckExtendClass)(e,n,this.isNot);else throw Error(`toExtendClass matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toImplementInterface(e,n){let r;if(e.type===`ClassLocator`)r=(0,t.classCheckImplementInterface)(e,n,this.isNot);else throw Error(`toImplementInterface matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toHaveExplicitReturnType(e){let n;if(e.type===`FunctionLocator`)n=(0,t.functionCheckHaveExplicitReturnType)(e,this.isNot);else throw Error(`toHaveExplicitReturnType matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toBeReadonly(e){let n;if(e.type===`PropertyLocator`)n=(0,t.propertyCheckBeReadonly)(e,this.isNot);else throw Error(`toBeReadonly matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toDependOnFilesInFolder(e,n){let r;if(e.type===`FileLocator`)r=(0,t.checkDependOnFilesInFolder)(e,n,this.isNot);else throw Error(`toDependOnFilesInFolder matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toDependOnExternalModule(e,n){let r;if(e.type===`FileLocator`)r=(0,t.checkDependOnExternalModule)(e,n,this.isNot);else throw Error(`toDependOnExternalModule matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toBeFreeOfCycles(e){let n;if(e.type===`FileLocator`)n=(0,t.fileCheckBeFreeOfCycles)(e,this.isNot);else if(e.type===`SliceLocator`)n=(0,t.sliceCheckBeFreeOfCycles)(e,this.isNot);else throw Error(`toBeFreeOfCycles matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toMatchNamePattern(e,n){let r;if(e.type===`FileLocator`)r=(0,t.fileCheckMatchNamePattern)(e,n,this.isNot);else if(e.type===`ClassLocator`)r=(0,t.classCheckMatchNamePattern)(e,n,this.isNot);else if(e.type===`FunctionLocator`)r=(0,t.functionCheckMatchNamePattern)(e,n,this.isNot);else throw Error(`toMatchNamePattern matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toHaveMaxCyclomaticComplexity(e,n){let r;if(e.type===`FileLocator`)r=(0,t.fileCheckHaveMaxCyclomaticComplexity)(e,n,this.isNot);else if(e.type===`ClassLocator`)r=(0,t.classCheckHaveMaxCyclomaticComplexity)(e,n,this.isNot);else if(e.type===`FunctionLocator`)r=(0,t.functionCheckHaveMaxCyclomaticComplexity)(e,n,this.isNot);else throw Error(`toHaveMaxCyclomaticComplexity matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toHaveMinMaintainabilityIndex(e,n){let r;if(e.type===`FileLocator`)r=(0,t.fileCheckHaveMinMaintainabilityIndex)(e,n,this.isNot);else if(e.type===`FunctionLocator`)r=(0,t.functionCheckHaveMinMaintainabilityIndex)(e,n,this.isNot);else throw Error(`toHaveMinMaintainabilityIndex matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toHaveMaxDistanceFromMainSequence(e,n){let r;if(e.type===`SliceLocator`)r=(0,t.sliceCheckHaveMaxDistanceFromMainSequence)(e,n,this.isNot);else throw Error(`toHaveMaxDistanceFromMainSequence matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}},toHaveNameMatchingFileName(e){let n;if(e.type===`FunctionLocator`)n=(0,t.functionCheckHaveNameMatchingFileName)(e,this.isNot);else if(e.type===`ClassLocator`)n=(0,t.classCheckHaveNameMatchingFileName)(e,this.isNot);else throw Error(`toHaveNameMatchingFileName matcher does not support ${e.type}`);return{pass:this.isNot?!n.pass:n.pass,message:n.message}},toHaveMaxExportedFunctions(e,n){let r;if(e.type===`FileLocator`)r=(0,t.fileCheckHaveMaxExportedFunctions)(e,n,this.isNot);else throw Error(`toHaveMaxExportedFunctions matcher does not support ${e.type}`);return{pass:this.isNot?!r.pass:r.pass,message:r.message}}})}Object.defineProperty(e,"parseProject",{enumerable:!0,get:function(){return t.parseProject}}),e.setupMatchers=r});
|
|
14
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/core/classes/classCheckExtendClass.ts","../src/core/metrics/calculateCyclomaticComplexity.ts","../src/core/utils/ruleBuilder.ts","../src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.ts","../src/core/classes/classCheckHaveMaxCyclomaticComplexity.ts","../src/core/shared/sharedCheckHaveModifier.ts","../src/core/classes/classCheckHaveModifier.ts","../src/core/shared/sharedCheckHaveNameMatchingFileName.ts","../src/core/classes/classCheckHaveNameMatchingFileName.ts","../src/core/classes/classCheckImplementInterface.ts","../src/core/shared/sharedCheckMatchNamePattern.ts","../src/core/classes/classCheckMatchNamePattern.ts","../src/core/classes/classCheckResideInFolder.ts","../src/core/classes/locateClasses.ts","../src/core/files/getFileDependencies.ts","../src/core/files/checkDependOnFilesInFolder.ts","../src/core/files/fileCheckBeFreeOfCycles.ts","../src/core/files/fileCheckHaveMaxCyclomaticComplexity.ts","../src/core/files/fileCheckHaveMaxExportedFunctions.ts","../src/core/metrics/calculateMaintainabilityIndex.ts","../src/core/shared/sharedCheckHaveMinMaintainabilityIndex.ts","../src/core/files/fileCheckHaveMinMaintainabilityIndex.ts","../src/core/files/fileCheckMatchNamePattern.ts","../src/core/files/locateFiles.ts","../src/core/functions/functionCheckHaveExplicitReturnType.ts","../src/core/functions/functionCheckHaveMaxCyclomaticComplexity.ts","../src/core/functions/functionCheckHaveMinMaintainabilityIndex.ts","../src/core/functions/functionCheckHaveModifier.ts","../src/core/functions/functionCheckHaveNameMatchingFileName.ts","../src/core/functions/functionCheckMatchNamePattern.ts","../src/core/functions/locateFunctions.ts","../src/core/layers/checkLayeredArchitecture.ts","../src/core/layers/createLayeredArchitecture.ts","../src/core/layers/layer.ts","../src/core/layers/getLayerDependencies.ts","../src/core/layers/layerShouldNotBeAccessedByAnyLayer.ts","../src/core/layers/layerShouldOnlyBeAccessedBy.ts","../src/core/properties/locateProperties.ts","../src/core/slices/locateSlices.ts","../src/core/project/parseProject.ts","../src/core/properties/propertyCheckBeReadonly.ts","../src/core/slices/sliceCheckBeFreeOfCycles.ts","../src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.ts","../src/matchers/index.ts"],"sourcesContent":["import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckExtendClass(\n locator: ClassLocatorData,\n className: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const c of locator.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 (\n ts.isIdentifier(type.expression) &&\n type.expression.text === className\n ) {\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(\n `Class ${name} does not extend ${className}, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\n\nexport function calculateCyclomaticComplexity(node: ts.Node): number {\n let complexity = 1;\n\n const visit = (n: ts.Node) => {\n switch (n.kind) {\n case ts.SyntaxKind.IfStatement:\n case ts.SyntaxKind.ForStatement:\n case ts.SyntaxKind.ForInStatement:\n case ts.SyntaxKind.ForOfStatement:\n case ts.SyntaxKind.WhileStatement:\n case ts.SyntaxKind.DoStatement:\n case ts.SyntaxKind.CaseClause:\n case ts.SyntaxKind.CatchClause:\n case ts.SyntaxKind.ConditionalExpression:\n complexity++;\n break;\n case ts.SyntaxKind.BinaryExpression: {\n const binary = n as ts.BinaryExpression;\n if (\n binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||\n binary.operatorToken.kind === ts.SyntaxKind.BarBarToken ||\n binary.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken\n ) {\n complexity++;\n }\n break;\n }\n }\n ts.forEachChild(n, visit);\n };\n\n ts.forEachChild(node, visit);\n return complexity;\n}\n","import type { RuleResult } from '../types';\n\nexport function ruleBuilder<T>(\n items: T[],\n isNot: boolean,\n evaluate: (item: T) => {\n passes: boolean;\n failMessage: string;\n failNotMessage: string;\n },\n): RuleResult {\n const violations: string[] = [];\n\n for (const item of items) {\n const { passes, failMessage, failNotMessage } = evaluate(item);\n\n if (isNot && passes) {\n if (failNotMessage) violations.push(failNotMessage);\n } else if (!isNot && !passes) {\n if (failMessage) violations.push(failMessage);\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveMaxCyclomaticComplexity<T>(\n items: T[],\n getName: (item: T) => string | undefined,\n getComplexity: (item: T) => number,\n label: string,\n max: number,\n isNot: boolean,\n) {\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const complexity = getComplexity(item);\n const exceeds = complexity > max;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes: !exceeds,\n failMessage: `${desc} has a total cyclomatic complexity of ${complexity}, which exceeds the maximum of ${max}.`,\n failNotMessage: `${desc} has a total cyclomatic complexity of ${complexity}, which exceeds the maximum of ${max}, but it shouldn't.`,\n };\n });\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from '../metrics/calculateCyclomaticComplexity';\nimport { sharedCheckHaveMaxCyclomaticComplexity } from '../shared/sharedCheckHaveMaxCyclomaticComplexity';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckHaveMaxCyclomaticComplexity(\n locator: ClassLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMaxCyclomaticComplexity(\n locator.classes,\n (c) => c.name?.text,\n (c) => {\n let complexity = 0;\n const visit = (node: ts.Node) => {\n if (\n ts.isMethodDeclaration(node) ||\n ts.isConstructorDeclaration(node) ||\n ts.isGetAccessor(node) ||\n ts.isSetAccessor(node)\n ) {\n complexity += calculateCyclomaticComplexity(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(c);\n return complexity;\n },\n 'Class',\n max,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveModifier<T extends ts.Node>(\n items: T[],\n getName: (item: T) => string | undefined,\n label: string,\n modifierStr: string,\n isNot: boolean,\n) {\n let targetKind: ts.SyntaxKind;\n switch (modifierStr) {\n case 'export':\n targetKind = ts.SyntaxKind.ExportKeyword;\n break;\n case 'default':\n targetKind = ts.SyntaxKind.DefaultKeyword;\n break;\n case 'abstract':\n targetKind = ts.SyntaxKind.AbstractKeyword;\n break;\n case 'async':\n targetKind = ts.SyntaxKind.AsyncKeyword;\n break;\n case 'public':\n targetKind = ts.SyntaxKind.PublicKeyword;\n break;\n case 'private':\n targetKind = ts.SyntaxKind.PrivateKeyword;\n break;\n default:\n throw new Error(`Modifier ${modifierStr} is not fully supported.`);\n }\n\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const modifiers = ts.canHaveModifiers(item)\n ? ts.getModifiers(item)\n : undefined;\n const passes = modifiers\n ? modifiers.some((m: ts.Modifier) => m.kind === targetKind)\n : false;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes,\n failMessage: `${desc} does not have modifier ${modifierStr}, but it should.`,\n failNotMessage: `${desc} has modifier ${modifierStr}, but it shouldn't.`,\n };\n });\n}\n","import { sharedCheckHaveModifier } from '../shared/sharedCheckHaveModifier';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckHaveModifier(\n locator: ClassLocatorData,\n modifierStr: string,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveModifier(\n locator.classes,\n (c) => c.name?.text,\n 'Class',\n modifierStr,\n isNot,\n );\n}\n","import * as path from 'node:path';\nimport * as ts from 'typescript';\nimport { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveNameMatchingFileName<T extends ts.Node>(\n items: T[],\n getName: (item: T) => string | undefined,\n label: string,\n isNot: boolean,\n) {\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const sourceFile = item.getSourceFile\n ? item.getSourceFile()\n : item.parent\n ? ts.getSourceFileOfNode(item)\n : undefined;\n\n if (!sourceFile) {\n return { passes: true, failMessage: '', failNotMessage: '' };\n }\n\n const basename = path.basename(\n sourceFile.fileName,\n path.extname(sourceFile.fileName),\n );\n const passes = name === basename;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes,\n failMessage: `${desc} does not have a name matching its filename ${basename}, but it should.`,\n failNotMessage: `${desc} has a name matching its filename ${basename}, but it shouldn't.`,\n };\n });\n}\n","import { sharedCheckHaveNameMatchingFileName } from '../shared/sharedCheckHaveNameMatchingFileName';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckHaveNameMatchingFileName(\n locator: ClassLocatorData,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveNameMatchingFileName(\n locator.classes,\n (c) => c.name?.text,\n 'Class',\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckImplementInterface(\n locator: ClassLocatorData,\n interfaceName: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const c of locator.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 (\n ts.isIdentifier(type.expression) &&\n type.expression.text === interfaceName\n ) {\n matches = true;\n break;\n }\n }\n }\n }\n }\n if (isNot && matches) {\n violations.push(\n `Class ${name} implements ${interfaceName}, but it shouldn't.`,\n );\n } else if (!isNot && !matches) {\n violations.push(\n `Class ${name} does not implement ${interfaceName}, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckMatchNamePattern<T>(\n items: T[],\n getName: (item: T) => string | undefined,\n label: string,\n pattern: string | RegExp,\n isNot: boolean,\n) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const passes = name ? regex.test(name) : false;\n const desc = `${label} ${name || 'Anonymous'}`;\n return {\n passes,\n failMessage: `${desc} does not match pattern ${pattern}, but it should.`,\n failNotMessage: `${desc} matches pattern ${pattern}, but it shouldn't.`,\n };\n });\n}\n","import { sharedCheckMatchNamePattern } from '../shared/sharedCheckMatchNamePattern';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckMatchNamePattern(\n locator: ClassLocatorData,\n pattern: string | RegExp,\n isNot: boolean,\n): RuleResult {\n return sharedCheckMatchNamePattern(\n locator.classes,\n (c) => c.name?.text,\n 'Class',\n pattern,\n isNot,\n );\n}\n","import type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckResideInFolder(\n locator: ClassLocatorData,\n targetFolder: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const c of locator.classes) {\n const className = c.name?.text || 'Anonymous Class';\n const sourceFile = c.getSourceFile();\n const inTargetFolder =\n sourceFile.fileName.includes(`/${targetFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${targetFolder}\\\\`);\n\n if (isNot && inTargetFolder) {\n violations.push(\n `Class ${className} resides in ${targetFolder}, but it shouldn't.`,\n );\n } else if (!isNot && !inTargetFolder) {\n violations.push(\n `Class ${className} does not reside in ${targetFolder}, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\nimport type { ClassLocatorData, ClassQueryOptions } from './types';\n\nexport function locateClasses(\n classes: ts.ClassDeclaration[],\n program: ts.Program,\n options?: ClassQueryOptions,\n): ClassLocatorData {\n let filtered = classes;\n\n if (options?.inFolder) {\n filtered = filtered.filter((c) => {\n const sourceFile = c.getSourceFile\n ? c.getSourceFile()\n : c.parent\n ? ts.getSourceFileOfNode(c)\n : undefined;\n if (!sourceFile) return false;\n return (\n sourceFile.fileName.includes(`/${options.inFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`)\n );\n });\n }\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : 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)\n ? ts.getDecorators(c)\n : 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 (\n ts.isCallExpression(exp) &&\n ts.isIdentifier(exp.expression)\n ) {\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 (\n ts.isIdentifier(type.expression) &&\n type.expression.text === options.extending\n ) {\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 (\n ts.isIdentifier(type.expression) &&\n type.expression.text === options.implementing\n ) {\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':\n targetKind = ts.SyntaxKind.ExportKeyword;\n break;\n case 'default':\n targetKind = ts.SyntaxKind.DefaultKeyword;\n break;\n case 'abstract':\n targetKind = ts.SyntaxKind.AbstractKeyword;\n break;\n default:\n throw new Error(\n `Modifier ${options.havingModifier} is not fully supported.`,\n );\n }\n filtered = filtered.filter((c) => {\n const modifiers = ts.canHaveModifiers(c) ? ts.getModifiers(c) : undefined;\n return modifiers?.some((m: ts.Modifier) => m.kind === targetKind);\n });\n }\n\n return {\n type: 'ClassLocator',\n classes: filtered,\n program,\n };\n}\n","import * as ts from 'typescript';\n\nexport function getFileDependencies(\n sourceFile: ts.SourceFile,\n program: ts.Program,\n): string[] {\n const dependencies: string[] = [];\n const compilerOptions = 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?.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?.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","import type { RuleResult } from '../types';\nimport { getFileDependencies } from './getFileDependencies';\nimport type { FileLocatorData } from './types';\n\nexport function checkDependOnFilesInFolder(\n locator: FileLocatorData,\n targetFolder: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n\n for (const file of locator.files) {\n const dependencies = getFileDependencies(file, locator.program);\n\n const dependsOnTarget = dependencies.some(\n (depPath) =>\n depPath.includes(`/${targetFolder}/`) ||\n depPath.includes(`\\\\${targetFolder}\\\\`),\n );\n\n if (isNot && dependsOnTarget) {\n violations.push(\n `File ${file.fileName} depends on files in ${targetFolder}, but it shouldn't.`,\n );\n } else if (!isNot && !dependsOnTarget) {\n violations.push(\n `File ${file.fileName} does not depend on files in ${targetFolder}, but it should.`,\n );\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import type { RuleResult } from '../types';\nimport { getFileDependencies } from './getFileDependencies';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckBeFreeOfCycles(\n locator: FileLocatorData,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n const targetedFilePaths = new Set<string>(\n locator.files.map((f) => f.fileName),\n );\n const graph = new Map<string, string[]>();\n\n for (const file of locator.files) {\n const filePath = file.fileName;\n const dependencies = getFileDependencies(file, locator.program).filter(\n (p) => targetedFilePaths.has(p),\n );\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","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from '../metrics/calculateCyclomaticComplexity';\nimport { sharedCheckHaveMaxCyclomaticComplexity } from '../shared/sharedCheckHaveMaxCyclomaticComplexity';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckHaveMaxCyclomaticComplexity(\n locator: FileLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMaxCyclomaticComplexity(\n locator.files,\n (f) => f.fileName,\n (file) => {\n let complexity = 0;\n const visit = (node: ts.Node) => {\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isArrowFunction(node) ||\n ts.isFunctionExpression(node)\n ) {\n complexity += calculateCyclomaticComplexity(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(file);\n return complexity;\n },\n 'File',\n max,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckHaveMaxExportedFunctions(\n locator: FileLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const file of locator.files) {\n let exportedFuncCount = 0;\n\n ts.forEachChild(file, (node) => {\n if (ts.isFunctionDeclaration(node)) {\n const modifiers = ts.canHaveModifiers(node)\n ? ts.getModifiers(node)\n : undefined;\n if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {\n exportedFuncCount++;\n }\n }\n });\n\n const exceeds = exportedFuncCount > max;\n\n if (isNot && exceeds) {\n violations.push(\n `File ${file.fileName} has ${exportedFuncCount} exported functions, which exceeds the maximum of ${max}, but it shouldn't.`,\n );\n } else if (!isNot && exceeds) {\n violations.push(\n `File ${file.fileName} has ${exportedFuncCount} exported functions, which exceeds the maximum of ${max}.`,\n );\n }\n }\n return {\n pass: isNot ? violations.length > 0 : violations.length === 0,\n message: () =>\n violations.join('\\n') ||\n (isNot\n ? 'Expected some files to exceed maximum exported functions, but none did.'\n : ''),\n };\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from './calculateCyclomaticComplexity';\n\nexport function calculateMaintainabilityIndex(node: ts.Node): number {\n let operators = 0;\n let operands = 0;\n const uniqueOperators = new Set<number>();\n const uniqueOperands = new Set<string>();\n let linesOfCode = 1;\n\n const sourceFile = node.getSourceFile();\n if (sourceFile) {\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n linesOfCode = end.line - start.line + 1;\n }\n\n const visit = (n: ts.Node) => {\n if (\n ts.isBinaryExpression(n) ||\n ts.isPrefixUnaryExpression(n) ||\n ts.isPostfixUnaryExpression(n)\n ) {\n operators++;\n uniqueOperators.add(n.kind);\n } else if (ts.isIdentifier(n) || ts.isLiteralExpression(n)) {\n operands++;\n uniqueOperands.add(n.getText(sourceFile));\n }\n ts.forEachChild(n, visit);\n };\n\n visit(node);\n\n const N = operators + operands;\n const n = uniqueOperators.size + uniqueOperands.size;\n const V = n === 0 ? 0 : N * Math.log2(n);\n const CC = calculateCyclomaticComplexity(node);\n\n const mi = Math.max(\n 0,\n ((171 - 5.2 * Math.log(V || 1) - 0.23 * CC - 16.2 * Math.log(linesOfCode)) *\n 100) /\n 171,\n );\n return mi;\n}\n","import { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveMinMaintainabilityIndex<T>(\n items: T[],\n getName: (item: T) => string | undefined,\n getMi: (item: T) => number,\n label: string,\n min: number,\n isNot: boolean,\n) {\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const mi = getMi(item);\n const fallsBelow = mi < min;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes: !fallsBelow,\n failMessage: `${desc} has a maintainability index of ${mi.toFixed(2)}, which falls below the minimum of ${min}.`,\n failNotMessage: `${desc} has a maintainability index of ${mi.toFixed(2)}, which falls below the minimum of ${min}, but it shouldn't.`,\n };\n });\n}\n","import { calculateMaintainabilityIndex } from '../metrics/calculateMaintainabilityIndex';\nimport { sharedCheckHaveMinMaintainabilityIndex } from '../shared/sharedCheckHaveMinMaintainabilityIndex';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckHaveMinMaintainabilityIndex(\n locator: FileLocatorData,\n min: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMinMaintainabilityIndex(\n locator.files,\n (f) => f.fileName,\n calculateMaintainabilityIndex,\n 'File',\n min,\n isNot,\n );\n}\n","import { sharedCheckMatchNamePattern } from '../shared/sharedCheckMatchNamePattern';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckMatchNamePattern(\n locator: FileLocatorData,\n pattern: string | RegExp,\n isNot: boolean,\n): RuleResult {\n return sharedCheckMatchNamePattern(\n locator.files,\n (f) => f.fileName,\n 'File',\n pattern,\n isNot,\n );\n}\n","import type * as ts from 'typescript';\nimport type { FileLocatorData, FileQueryOptions } from './types';\n\nexport function locateFiles(\n sourceFiles: ts.SourceFile[],\n program: ts.Program,\n options?: FileQueryOptions,\n): FileLocatorData {\n let filtered = sourceFiles;\n\n if (options?.inFolder) {\n filtered = filtered.filter(\n (file) =>\n file.fileName.includes(`/${options.inFolder}/`) ||\n file.fileName.includes(`\\\\${options.inFolder}\\\\`),\n );\n }\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : options.matchNamePattern;\n filtered = filtered.filter((file) => regex.test(file.fileName));\n }\n\n return {\n type: 'FileLocator',\n files: filtered,\n program,\n };\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveExplicitReturnType(\n locator: FunctionLocatorData,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const f of locator.functions) {\n const name =\n f.name && ts.isIdentifier(f.name) ? f.name.text : 'Anonymous Function';\n const hasType = !!f.type;\n\n if (isNot && hasType) {\n violations.push(\n `Function ${name} has an explicit return type, but it shouldn't.`,\n );\n } else if (!isNot && !hasType) {\n violations.push(\n `Function ${name} does not have an explicit return type, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from '../metrics/calculateCyclomaticComplexity';\nimport { sharedCheckHaveMaxCyclomaticComplexity } from '../shared/sharedCheckHaveMaxCyclomaticComplexity';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveMaxCyclomaticComplexity(\n locator: FunctionLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMaxCyclomaticComplexity(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n calculateCyclomaticComplexity,\n 'Function',\n max,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { calculateMaintainabilityIndex } from '../metrics/calculateMaintainabilityIndex';\nimport { sharedCheckHaveMinMaintainabilityIndex } from '../shared/sharedCheckHaveMinMaintainabilityIndex';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveMinMaintainabilityIndex(\n locator: FunctionLocatorData,\n min: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMinMaintainabilityIndex(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n calculateMaintainabilityIndex,\n 'Function',\n min,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { sharedCheckHaveModifier } from '../shared/sharedCheckHaveModifier';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveModifier(\n locator: FunctionLocatorData,\n modifierStr: string,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveModifier(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n 'Function',\n modifierStr,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { sharedCheckHaveNameMatchingFileName } from '../shared/sharedCheckHaveNameMatchingFileName';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveNameMatchingFileName(\n locator: FunctionLocatorData,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveNameMatchingFileName(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n 'Function',\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { sharedCheckMatchNamePattern } from '../shared/sharedCheckMatchNamePattern';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckMatchNamePattern(\n locator: FunctionLocatorData,\n pattern: string | RegExp,\n isNot: boolean,\n): RuleResult {\n return sharedCheckMatchNamePattern(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n 'Function',\n pattern,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport type { FunctionLocatorData, FunctionQueryOptions } from './types';\n\nexport function locateFunctions(\n functions: ts.FunctionLikeDeclaration[],\n program: ts.Program,\n options?: FunctionQueryOptions,\n): FunctionLocatorData {\n let filtered = functions;\n\n if (options?.inFolder) {\n filtered = filtered.filter((f) => {\n const sourceFile = f.getSourceFile\n ? f.getSourceFile()\n : f.parent\n ? ts.getSourceFileOfNode(f)\n : undefined;\n if (!sourceFile) return false;\n return (\n sourceFile.fileName.includes(`/${options.inFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`)\n );\n });\n }\n\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : 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 return {\n type: 'FunctionLocator',\n functions: filtered,\n program,\n };\n}\n","import type { RuleResult } from '../types';\nimport type { LayeredArchitectureData } from './types';\n\nexport function checkLayeredArchitecture(\n data: LayeredArchitectureData,\n): RuleResult {\n const violations: string[] = [];\n for (const assertion of data.assertions) {\n violations.push(...assertion(data.files));\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import type * as ts from 'typescript';\nimport type { LayeredArchitectureData } from './types';\n\nexport function createLayeredArchitecture(\n files: ts.SourceFile[],\n program: ts.Program,\n): LayeredArchitectureData {\n return {\n type: 'LayeredArchitecture',\n files,\n layers: new Map<string, string>(),\n assertions: [],\n program,\n };\n}\n","import type { LayeredArchitectureData } from './types';\n\nexport function layer(\n data: LayeredArchitectureData,\n name: string,\n folderPattern: string,\n): LayeredArchitectureData {\n data.layers.set(name, folderPattern);\n return data;\n}\n","import * as ts from 'typescript';\n\nexport function getLayerDependencies(\n sourceFile: ts.SourceFile,\n program: ts.Program,\n): string[] {\n const dependencies: string[] = [];\n const compilerOptions = 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 (\n resolved.resolvedModule?.resolvedFileName &&\n !resolved.resolvedModule.isExternalLibraryImport\n ) {\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(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys,\n );\n if (\n resolved.resolvedModule?.resolvedFileName &&\n !resolved.resolvedModule.isExternalLibraryImport\n ) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return dependencies;\n}\n","import { getLayerDependencies } from './getLayerDependencies';\nimport type { LayeredArchitectureData } from './types';\n\nexport function layerShouldNotBeAccessedByAnyLayer(\n data: LayeredArchitectureData,\n targetLayer: string,\n): LayeredArchitectureData {\n if (!data.layers.has(targetLayer)) {\n throw new Error(`Layer ${targetLayer} is not defined`);\n }\n\n data.assertions.push((files) => {\n const violations: string[] = [];\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const targetPattern = data.layers.get(targetLayer)!;\n\n for (const file of files) {\n const filePath = file.fileName;\n if (\n !filePath.includes(`/${targetPattern}/`) &&\n !filePath.includes(`\\\\${targetPattern}\\\\`)\n ) {\n const dependencies = getLayerDependencies(file, data.program);\n const importsTarget = dependencies.some(\n (dep) =>\n dep.includes(`/${targetPattern}/`) ||\n dep.includes(`\\\\${targetPattern}\\\\`),\n );\n if (importsTarget) {\n violations.push(\n `File ${filePath} accesses layer ${targetLayer} but it shouldn't.`,\n );\n }\n }\n }\n return violations;\n });\n\n return data;\n}\n","import { getLayerDependencies } from './getLayerDependencies';\nimport type { LayeredArchitectureData } from './types';\n\nexport function layerShouldOnlyBeAccessedBy(\n data: LayeredArchitectureData,\n targetLayer: string,\n allowedLayers: string[],\n): LayeredArchitectureData {\n if (!data.layers.has(targetLayer)) {\n throw new Error(`Layer ${targetLayer} is not defined`);\n }\n\n data.assertions.push((files) => {\n const violations: string[] = [];\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const targetPattern = data.layers.get(targetLayer)!;\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const allowedPatterns = allowedLayers.map((l) => data.layers.get(l)!);\n\n for (const file of files) {\n const filePath = file.fileName;\n const isInAllowedLayer = allowedPatterns.some(\n (p) => filePath.includes(`/${p}/`) || filePath.includes(`\\\\${p}\\\\`),\n );\n\n if (\n !filePath.includes(`/${targetPattern}/`) &&\n !filePath.includes(`\\\\${targetPattern}\\\\`) &&\n !isInAllowedLayer\n ) {\n const dependencies = getLayerDependencies(file, data.program);\n const importsTarget = dependencies.some(\n (dep) =>\n dep.includes(`/${targetPattern}/`) ||\n dep.includes(`\\\\${targetPattern}\\\\`),\n );\n if (importsTarget) {\n violations.push(\n `File ${filePath} accesses layer ${targetLayer} but only ${allowedLayers.join(', ')} are allowed.`,\n );\n }\n }\n }\n return violations;\n });\n\n return data;\n}\n","import * as ts from 'typescript';\nimport type { PropertyLocatorData, PropertyQueryOptions } from './types';\n\nexport function locateProperties(\n properties: ts.PropertyDeclaration[],\n program: ts.Program,\n options?: PropertyQueryOptions,\n): PropertyLocatorData {\n let filtered = properties;\n\n if (options?.inFolder) {\n filtered = filtered.filter((p) => {\n const sourceFile = p.getSourceFile\n ? p.getSourceFile()\n : p.parent\n ? ts.getSourceFileOfNode(p)\n : undefined;\n if (!sourceFile) return false;\n return (\n sourceFile.fileName.includes(`/${options.inFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`)\n );\n });\n }\n\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : options.matchNamePattern;\n filtered = filtered.filter((p) => {\n return ts.isIdentifier(p.name) && regex.test(p.name.text);\n });\n }\n\n return {\n type: 'PropertyLocator',\n properties: filtered,\n program,\n };\n}\n","import type * as ts from 'typescript';\nimport type { SliceLocatorData } from './types';\n\nexport function locateSlices(\n sourceFiles: ts.SourceFile[],\n program: ts.Program,\n pattern: string,\n): SliceLocatorData {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regexStr = escaped.replace(/\\*/g, '([^/\\\\\\\\]+)');\n const slicePattern = new RegExp(regexStr);\n\n const sliceIds = new Set<string>();\n const sliceFiles = new Map<string, ts.SourceFile[]>();\n\n for (const sf of sourceFiles) {\n const match = sf.fileName.match(slicePattern);\n if (match?.[1]) {\n const sliceId = match[1];\n sliceIds.add(sliceId);\n if (!sliceFiles.has(sliceId)) {\n sliceFiles.set(sliceId, []);\n }\n sliceFiles.get(sliceId)?.push(sf);\n }\n }\n\n return {\n type: 'SliceLocator',\n slicePattern,\n sliceIds,\n sliceFiles,\n program,\n };\n}\n","import { dirname } from 'node:path';\nimport * as ts from 'typescript';\nimport { locateClasses } from '../classes/locateClasses';\nimport type { ClassQueryOptions } from '../classes/types';\nimport { locateFiles } from '../files/locateFiles';\nimport type { FileQueryOptions } from '../files/types';\nimport { locateFunctions } from '../functions/locateFunctions';\nimport type { FunctionQueryOptions } from '../functions/types';\nimport { checkLayeredArchitecture } from '../layers/checkLayeredArchitecture';\nimport { createLayeredArchitecture } from '../layers/createLayeredArchitecture';\nimport { layer } from '../layers/layer';\nimport { layerShouldNotBeAccessedByAnyLayer } from '../layers/layerShouldNotBeAccessedByAnyLayer';\nimport { layerShouldOnlyBeAccessedBy } from '../layers/layerShouldOnlyBeAccessedBy';\nimport { locateProperties } from '../properties/locateProperties';\nimport type { PropertyQueryOptions } from '../properties/types';\nimport { locateSlices } from '../slices/locateSlices';\n\nexport function parseProject(options: { tsConfigFilePath?: string } = {}) {\n let compilerOptions: ts.CompilerOptions = {};\n const configPath =\n options.tsConfigFilePath ||\n ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');\n\n let program: ts.Program;\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 dirname(configPath),\n undefined,\n configPath,\n undefined,\n [\n {\n extension: '.vue',\n isMixedContent: true,\n scriptKind: ts.ScriptKind.TS,\n },\n {\n extension: '.svelte',\n isMixedContent: true,\n scriptKind: ts.ScriptKind.TS,\n },\n ],\n );\n compilerOptions = parsedCommandLine.options;\n\n const host = ts.createCompilerHost(compilerOptions);\n const originalGetSourceFile = host.getSourceFile;\n\n // biome-ignore lint/suspicious/noExplicitAny: Dynamic require\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 = (\n fileName,\n languageVersion,\n onError,\n shouldCreateNewSourceFile,\n ) => {\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 const match = content.match(/<script[^>]*>(.*?)<\\/script>/s);\n if (match) scriptContent = match[1];\n }\n return ts.createSourceFile(\n fileName,\n scriptContent,\n languageVersion,\n true,\n ts.ScriptKind.TS,\n );\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(\n fileName,\n scriptContent,\n languageVersion,\n true,\n ts.ScriptKind.TS,\n );\n }\n }\n\n return originalGetSourceFile(\n fileName,\n languageVersion,\n onError,\n shouldCreateNewSourceFile,\n );\n };\n\n program = ts.createProgram({\n rootNames: parsedCommandLine.fileNames,\n options: compilerOptions,\n host: host,\n });\n\n // Force the TypeScript compiler to bind the AST and populate .parent pointers\n program.getTypeChecker();\n } else {\n throw new Error('Could not find tsconfig.json');\n }\n\n const getSourceFiles = () =>\n program\n .getSourceFiles()\n .filter(\n (sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules'),\n );\n\n return {\n getFiles: (queryOptions?: FileQueryOptions) => {\n return locateFiles(getSourceFiles(), program, queryOptions);\n },\n\n getClasses: (queryOptions?: ClassQueryOptions) => {\n const allClasses: ts.ClassDeclaration[] = [];\n for (const sf of getSourceFiles()) {\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 locateClasses(allClasses, program, queryOptions);\n },\n\n layeredArchitecture: () => {\n let data = createLayeredArchitecture(getSourceFiles(), program);\n const api = {\n layer: (name: string, folderPattern: string) => {\n data = layer(data, name, folderPattern);\n return api;\n },\n whereLayer: (name: string) => {\n return {\n shouldNotBeAccessedByAnyLayer: () => {\n data = layerShouldNotBeAccessedByAnyLayer(data, name);\n return api;\n },\n shouldOnlyBeAccessedBy: (...allowedLayers: string[]) => {\n data = layerShouldOnlyBeAccessedBy(data, name, allowedLayers);\n return api;\n },\n };\n },\n check: () => checkLayeredArchitecture(data),\n get data() {\n return data;\n },\n };\n return api;\n },\n\n getFunctions: (queryOptions?: FunctionQueryOptions) => {\n const allFunctions: ts.FunctionLikeDeclaration[] = [];\n for (const sf of getSourceFiles()) {\n const visit = (node: ts.Node) => {\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isArrowFunction(node)\n ) {\n allFunctions.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return locateFunctions(allFunctions, program, queryOptions);\n },\n\n getProperties: (queryOptions?: PropertyQueryOptions) => {\n const allProperties: ts.PropertyDeclaration[] = [];\n for (const sf of getSourceFiles()) {\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 locateProperties(allProperties, program, queryOptions);\n },\n\n getSlices: (pattern: string) => {\n return locateSlices(getSourceFiles(), program, pattern);\n },\n };\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { PropertyLocatorData } from './types';\n\nexport function propertyCheckBeReadonly(\n locator: PropertyLocatorData,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const p of locator.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?.some(\n (m: ts.Modifier) => m.kind === ts.SyntaxKind.ReadonlyKeyword,\n );\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","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { SliceLocatorData } from './types';\n\nexport function sliceCheckBeFreeOfCycles(\n locator: SliceLocatorData,\n isNot: boolean,\n): RuleResult {\n const graph: Map<string, Set<string>> = new Map();\n for (const slice of locator.sliceIds) {\n graph.set(slice, new Set());\n }\n\n for (const [sliceId, files] of locator.sliceFiles.entries()) {\n for (const sf of files) {\n ts.forEachChild(sf, (node) => {\n if (\n ts.isImportDeclaration(node) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n ) {\n const importPath = node.moduleSpecifier.text;\n const resolved = ts.resolveModuleName(\n importPath,\n sf.fileName,\n locator.program.getCompilerOptions(),\n ts.sys,\n );\n if (resolved.resolvedModule?.resolvedFileName) {\n const targetMatch = resolved.resolvedModule.resolvedFileName.match(\n locator.slicePattern,\n );\n if (targetMatch?.[1]) {\n const targetSlice = targetMatch[1];\n if (\n targetSlice !== sliceId &&\n locator.sliceIds.has(targetSlice)\n ) {\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(\n `Cycle detected between slices: ${path.join(' -> ')} -> ${neighbor}`,\n );\n return true;\n }\n }\n\n recursionStack.delete(node);\n return false;\n };\n\n for (const slice of locator.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: () =>\n violations.length > 0\n ? ''\n : '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","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { SliceLocatorData } from './types';\n\nexport function sliceCheckHaveMaxDistanceFromMainSequence(\n locator: SliceLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n\n const ceMap = new Map<string, Set<string>>(); // Slices this slice depends on\n const caMap = new Map<string, Set<string>>(); // Slices depending on this slice\n\n for (const slice of locator.sliceIds) {\n ceMap.set(slice, new Set());\n caMap.set(slice, new Set());\n }\n\n for (const [sliceId, files] of locator.sliceFiles.entries()) {\n for (const sf of files) {\n ts.forEachChild(sf, (node) => {\n if (\n ts.isImportDeclaration(node) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n ) {\n const importPath = node.moduleSpecifier.text;\n const resolved = ts.resolveModuleName(\n importPath,\n sf.fileName,\n locator.program.getCompilerOptions(),\n ts.sys,\n );\n if (resolved.resolvedModule?.resolvedFileName) {\n const targetMatch = resolved.resolvedModule.resolvedFileName.match(\n locator.slicePattern,\n );\n if (targetMatch?.[1]) {\n const targetSlice = targetMatch[1];\n if (\n targetSlice !== sliceId &&\n locator.sliceIds.has(targetSlice)\n ) {\n ceMap.get(sliceId)?.add(targetSlice);\n caMap.get(targetSlice)?.add(sliceId);\n }\n }\n }\n }\n });\n }\n }\n\n for (const sliceId of locator.sliceIds) {\n const ce = ceMap.get(sliceId)?.size;\n const ca = caMap.get(sliceId)?.size;\n\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const files = locator.sliceFiles.get(sliceId)!;\n let na = 0; // abstract classes + interfaces\n let nc = 0; // all classes + interfaces\n\n for (const sf of files) {\n const visit = (node: ts.Node) => {\n if (ts.isClassDeclaration(node)) {\n nc++;\n const modifiers = ts.canHaveModifiers(node)\n ? ts.getModifiers(node)\n : undefined;\n if (\n modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword)\n ) {\n na++;\n }\n } else if (ts.isInterfaceDeclaration(node)) {\n nc++;\n na++;\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n\n const I = ce + ca === 0 ? 0 : ce / (ca + ce);\n const A = nc === 0 ? 0 : na / nc;\n\n const D = Math.abs(A + I - 1);\n const exceeds = D > max;\n\n if (isNot && exceeds) {\n violations.push(\n `Slice ${sliceId} has a Distance from the Main Sequence of ${D.toFixed(2)}, which exceeds the maximum of ${max}, but it shouldn't.`,\n );\n } else if (!isNot && exceeds) {\n violations.push(\n `Slice ${sliceId} has a Distance from the Main Sequence of ${D.toFixed(2)}, which exceeds the maximum of ${max}.`,\n );\n }\n }\n\n return {\n pass: isNot ? violations.length > 0 : violations.length === 0,\n message: () =>\n violations.join('\\n') ||\n (isNot\n ? 'Expected some slices to exceed maximum distance from main sequence, but none did.'\n : ''),\n };\n}\n","import { expect } from 'vitest';\nimport { classCheckExtendClass } from '../core/classes/classCheckExtendClass';\nimport { classCheckHaveMaxCyclomaticComplexity } from '../core/classes/classCheckHaveMaxCyclomaticComplexity';\nimport { classCheckHaveModifier } from '../core/classes/classCheckHaveModifier';\nimport { classCheckHaveNameMatchingFileName } from '../core/classes/classCheckHaveNameMatchingFileName';\nimport { classCheckImplementInterface } from '../core/classes/classCheckImplementInterface';\nimport { classCheckMatchNamePattern } from '../core/classes/classCheckMatchNamePattern';\nimport { classCheckResideInFolder } from '../core/classes/classCheckResideInFolder';\nimport { checkDependOnFilesInFolder } from '../core/files/checkDependOnFilesInFolder';\nimport { fileCheckBeFreeOfCycles } from '../core/files/fileCheckBeFreeOfCycles';\nimport { fileCheckHaveMaxCyclomaticComplexity } from '../core/files/fileCheckHaveMaxCyclomaticComplexity';\nimport { fileCheckHaveMaxExportedFunctions } from '../core/files/fileCheckHaveMaxExportedFunctions';\nimport { fileCheckHaveMinMaintainabilityIndex } from '../core/files/fileCheckHaveMinMaintainabilityIndex';\nimport { fileCheckMatchNamePattern } from '../core/files/fileCheckMatchNamePattern';\nimport { functionCheckHaveExplicitReturnType } from '../core/functions/functionCheckHaveExplicitReturnType';\nimport { functionCheckHaveMaxCyclomaticComplexity } from '../core/functions/functionCheckHaveMaxCyclomaticComplexity';\nimport { functionCheckHaveMinMaintainabilityIndex } from '../core/functions/functionCheckHaveMinMaintainabilityIndex';\nimport { functionCheckHaveModifier } from '../core/functions/functionCheckHaveModifier';\nimport { functionCheckHaveNameMatchingFileName } from '../core/functions/functionCheckHaveNameMatchingFileName';\nimport { functionCheckMatchNamePattern } from '../core/functions/functionCheckMatchNamePattern';\nimport { checkLayeredArchitecture } from '../core/layers/checkLayeredArchitecture';\n\nimport { propertyCheckBeReadonly } from '../core/properties/propertyCheckBeReadonly';\n\nimport { sliceCheckBeFreeOfCycles } from '../core/slices/sliceCheckBeFreeOfCycles';\nimport { sliceCheckHaveMaxDistanceFromMainSequence } from '../core/slices/sliceCheckHaveMaxDistanceFromMainSequence';\nimport type { LocatorData, RuleResult } from '../core/types';\n\nexport function setupMatchers() {\n expect.extend({\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n toPass(received: any) {\n let result: RuleResult;\n\n if (received?.data && received.data.type === 'LayeredArchitecture') {\n result = checkLayeredArchitecture(received.data);\n } else {\n result = received as RuleResult;\n }\n\n const { pass, message } = result;\n return {\n pass: this.isNot ? !pass : pass,\n message: pass ? () => 'Expected rule not to pass' : () => message(),\n };\n },\n\n toResideInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckResideInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toResideInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveModifier(received: LocatorData, modifier: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckHaveModifier(received, modifier, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveModifier(received, modifier, this.isNot);\n } else {\n throw new Error(\n `toHaveModifier matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toExtendClass(received: LocatorData, className: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckExtendClass(received, className, this.isNot);\n } else {\n throw new Error(\n `toExtendClass matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toImplementInterface(received: LocatorData, interfaceName: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckImplementInterface(\n received,\n interfaceName,\n this.isNot,\n );\n } else {\n throw new Error(\n `toImplementInterface matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveExplicitReturnType(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveExplicitReturnType(received, this.isNot);\n } else {\n throw new Error(\n `toHaveExplicitReturnType matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeReadonly(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'PropertyLocator') {\n result = propertyCheckBeReadonly(received, this.isNot);\n } else {\n throw new Error(\n `toBeReadonly matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toDependOnFilesInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = checkDependOnFilesInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toDependOnFilesInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeFreeOfCycles(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckBeFreeOfCycles(received, this.isNot);\n } else if (received.type === 'SliceLocator') {\n result = sliceCheckBeFreeOfCycles(received, this.isNot);\n } else {\n throw new Error(\n `toBeFreeOfCycles matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toMatchNamePattern(received: LocatorData, pattern: string | RegExp) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckMatchNamePattern(received, pattern, this.isNot);\n } else {\n throw new Error(\n `toMatchNamePattern matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxCyclomaticComplexity(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxCyclomaticComplexity matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMinMaintainabilityIndex(received: LocatorData, min: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMinMaintainabilityIndex matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxDistanceFromMainSequence(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'SliceLocator') {\n result = sliceCheckHaveMaxDistanceFromMainSequence(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxDistanceFromMainSequence matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveNameMatchingFileName(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveNameMatchingFileName(received, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveNameMatchingFileName(received, this.isNot);\n } else {\n throw new Error(\n `toHaveNameMatchingFileName matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxExportedFunctions(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxExportedFunctions(received, max, this.isNot);\n } else {\n throw new Error(\n `toHaveMaxExportedFunctions matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n });\n}\n\ndeclare module 'vitest' {\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n interface Assertion<T = any> {\n toPass(): void;\n toResideInFolder(folder: string): void;\n toHaveModifier(\n modifier:\n | 'export'\n | 'default'\n | 'abstract'\n | 'async'\n | 'private'\n | 'public',\n ): void;\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 toHaveMaxCyclomaticComplexity(max: number): void;\n toHaveMinMaintainabilityIndex(min: number): void;\n toHaveMaxDistanceFromMainSequence(max: number): void;\n toHaveNameMatchingFileName(): void;\n toHaveMaxExportedFunctions(max: number): void;\n }\n}\n"],"mappings":"q4BAIA,SAAgB,EACd,EACA,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAQ,QAAS,CAC/B,IAAM,EAAO,EAAE,MAAM,MAAQ,YACzB,EAAU,GACd,GAAI,EAAE,qBACC,IAAM,KAAU,EAAE,gBACrB,GAAI,EAAO,QAAU,EAAG,WAAW,oBAC5B,IAAM,KAAQ,EAAO,MACxB,GACE,EAAG,aAAa,EAAK,WAAW,EAChC,EAAK,WAAW,OAAS,EACzB,CACA,EAAU,GACV,QAMN,GAAS,EACX,EAAW,KAAK,SAAS,EAAK,WAAW,EAAU,qBAAqB,CAC/D,CAAC,GAAS,CAAC,GACpB,EAAW,KACT,SAAS,EAAK,mBAAmB,EAAU,kBAC5C,CAGL,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCrCH,SAAgB,EAA8B,EAAuB,CACnE,IAAI,EAAa,EAEX,EAAS,GAAe,CAC5B,OAAQ,EAAE,KAAV,CACE,KAAK,EAAG,WAAW,YACnB,KAAK,EAAG,WAAW,aACnB,KAAK,EAAG,WAAW,eACnB,KAAK,EAAG,WAAW,eACnB,KAAK,EAAG,WAAW,eACnB,KAAK,EAAG,WAAW,YACnB,KAAK,EAAG,WAAW,WACnB,KAAK,EAAG,WAAW,YACnB,KAAK,EAAG,WAAW,sBACjB,IACA,MACF,KAAK,EAAG,WAAW,iBAAkB,CACnC,IAAM,EAAS,GAEb,EAAO,cAAc,OAAS,EAAG,WAAW,yBAC5C,EAAO,cAAc,OAAS,EAAG,WAAW,aAC5C,EAAO,cAAc,OAAS,EAAG,WAAW,wBAE5C,IAEF,OAGJ,EAAG,aAAa,EAAG,EAAM,EAI3B,OADA,EAAG,aAAa,EAAM,EAAM,CACrB,EChCT,SAAgB,EACd,EACA,EACA,EAKY,CACZ,IAAM,EAAuB,EAAE,CAE/B,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAM,CAAE,SAAQ,cAAa,kBAAmB,EAAS,EAAK,CAE1D,GAAS,EACP,GAAgB,EAAW,KAAK,EAAe,CAC1C,CAAC,GAAS,CAAC,GAChB,GAAa,EAAW,KAAK,EAAY,CAIjD,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCxBH,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,EACA,CACA,OAAO,EAAY,EAAO,EAAQ,GAAS,CACzC,IAAM,EAAO,EAAQ,EAAK,CACpB,EAAa,EAAc,EAAK,CAChC,EAAU,EAAa,EACvB,EAAO,GAAG,EAAM,GAAG,GAAQ,cAEjC,MAAO,CACL,OAAQ,CAAC,EACT,YAAa,GAAG,EAAK,wCAAwC,EAAW,iCAAiC,EAAI,GAC7G,eAAgB,GAAG,EAAK,wCAAwC,EAAW,iCAAiC,EAAI,qBACjH,EACD,CCfJ,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,QACP,GAAM,EAAE,MAAM,KACd,GAAM,CACL,IAAI,EAAa,EACX,EAAS,GAAkB,EAE7B,EAAG,oBAAoB,EAAK,EAC5B,EAAG,yBAAyB,EAAK,EACjC,EAAG,cAAc,EAAK,EACtB,EAAG,cAAc,EAAK,IAEtB,GAAc,EAA8B,EAAK,EAEnD,EAAG,aAAa,EAAM,EAAM,EAG9B,OADA,EAAM,EAAE,CACD,GAET,QACA,EACA,EACD,CC9BH,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,CACA,IAAI,EACJ,OAAQ,EAAR,CACE,IAAK,SACH,EAAa,EAAG,WAAW,cAC3B,MACF,IAAK,UACH,EAAa,EAAG,WAAW,eAC3B,MACF,IAAK,WACH,EAAa,EAAG,WAAW,gBAC3B,MACF,IAAK,QACH,EAAa,EAAG,WAAW,aAC3B,MACF,IAAK,SACH,EAAa,EAAG,WAAW,cAC3B,MACF,IAAK,UACH,EAAa,EAAG,WAAW,eAC3B,MACF,QACE,MAAU,MAAM,YAAY,EAAY,0BAA0B,CAGtE,OAAO,EAAY,EAAO,EAAQ,GAAS,CACzC,IAAM,EAAO,EAAQ,EAAK,CACpB,EAAY,EAAG,iBAAiB,EAAK,CACvC,EAAG,aAAa,EAAK,CACrB,IAAA,GACE,EAAS,EACX,EAAU,KAAM,GAAmB,EAAE,OAAS,EAAW,CACzD,GACE,EAAO,GAAG,EAAM,GAAG,GAAQ,cAEjC,MAAO,CACL,SACA,YAAa,GAAG,EAAK,0BAA0B,EAAY,kBAC3D,eAAgB,GAAG,EAAK,gBAAgB,EAAY,qBACrD,EACD,CC7CJ,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,QACP,GAAM,EAAE,MAAM,KACf,QACA,EACA,EACD,CCXH,SAAgB,EACd,EACA,EACA,EACA,EACA,CACA,OAAO,EAAY,EAAO,EAAQ,GAAS,CACzC,IAAM,EAAO,EAAQ,EAAK,CACpB,EAAa,EAAK,cACpB,EAAK,eAAe,CACpB,EAAK,OACH,EAAG,oBAAoB,EAAK,CAC5B,IAAA,GAEN,GAAI,CAAC,EACH,MAAO,CAAE,OAAQ,GAAM,YAAa,GAAI,eAAgB,GAAI,CAG9D,IAAM,EAAW,EAAK,SACpB,EAAW,SACX,EAAK,QAAQ,EAAW,SAAS,CAClC,CACK,EAAS,IAAS,EAClB,EAAO,GAAG,EAAM,GAAG,GAAQ,cAEjC,MAAO,CACL,SACA,YAAa,GAAG,EAAK,8CAA8C,EAAS,kBAC5E,eAAgB,GAAG,EAAK,oCAAoC,EAAS,qBACtE,EACD,CC9BJ,SAAgB,EACd,EACA,EACY,CACZ,OAAO,EACL,EAAQ,QACP,GAAM,EAAE,MAAM,KACf,QACA,EACD,CCTH,SAAgB,EACd,EACA,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAQ,QAAS,CAC/B,IAAM,EAAO,EAAE,MAAM,MAAQ,YACzB,EAAU,GACd,GAAI,EAAE,qBACC,IAAM,KAAU,EAAE,gBACrB,GAAI,EAAO,QAAU,EAAG,WAAW,uBAC5B,IAAM,KAAQ,EAAO,MACxB,GACE,EAAG,aAAa,EAAK,WAAW,EAChC,EAAK,WAAW,OAAS,EACzB,CACA,EAAU,GACV,QAMN,GAAS,EACX,EAAW,KACT,SAAS,EAAK,cAAc,EAAc,qBAC3C,CACQ,CAAC,GAAS,CAAC,GACpB,EAAW,KACT,SAAS,EAAK,sBAAsB,EAAc,kBACnD,CAGL,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCvCH,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,CACA,IAAM,EAAQ,OAAO,GAAY,SAAW,IAAI,OAAO,EAAQ,CAAG,EAElE,OAAO,EAAY,EAAO,EAAQ,GAAS,CACzC,IAAM,EAAO,EAAQ,EAAK,CACpB,EAAS,EAAO,EAAM,KAAK,EAAK,CAAG,GACnC,EAAO,GAAG,EAAM,GAAG,GAAQ,cACjC,MAAO,CACL,SACA,YAAa,GAAG,EAAK,0BAA0B,EAAQ,kBACvD,eAAgB,GAAG,EAAK,mBAAmB,EAAQ,qBACpD,EACD,CChBJ,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,QACP,GAAM,EAAE,MAAM,KACf,QACA,EACA,EACD,CCZH,SAAgB,EACd,EACA,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAQ,QAAS,CAC/B,IAAM,EAAY,EAAE,MAAM,MAAQ,kBAC5B,EAAa,EAAE,eAAe,CAC9B,EACJ,EAAW,SAAS,SAAS,IAAI,EAAa,GAAG,EACjD,EAAW,SAAS,SAAS,KAAK,EAAa,IAAI,CAEjD,GAAS,EACX,EAAW,KACT,SAAS,EAAU,cAAc,EAAa,qBAC/C,CACQ,CAAC,GAAS,CAAC,GACpB,EAAW,KACT,SAAS,EAAU,sBAAsB,EAAa,kBACvD,CAGL,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CC1BH,SAAgB,EACd,EACA,EACA,EACkB,CAClB,IAAI,EAAW,EAgBf,GAdI,GAAS,WACX,EAAW,EAAS,OAAQ,GAAM,CAChC,IAAM,EAAa,EAAE,cACjB,EAAE,eAAe,CACjB,EAAE,OACA,EAAG,oBAAoB,EAAE,CACzB,IAAA,GAEN,OADK,EAEH,EAAW,SAAS,SAAS,IAAI,EAAQ,SAAS,GAAG,EACrD,EAAW,SAAS,SAAS,KAAK,EAAQ,SAAS,IAAI,CAHjC,IAKxB,EAEA,GAAS,iBAAkB,CAC7B,IAAM,EACJ,OAAO,EAAQ,kBAAqB,SAChC,IAAI,OAAO,EAAQ,iBAAiB,CACpC,EAAQ,iBACd,EAAW,EAAS,OAAQ,GAAM,CAChC,IAAM,EAAO,EAAE,MAAM,KACrB,OAAO,GAAQ,EAAM,KAAK,EAAK,EAC/B,CAkEJ,GAhEI,GAAS,gBACX,EAAW,EAAS,OAAQ,GAAM,CAChC,IAAM,EAAa,EAAG,kBAAkB,EAAE,CACtC,EAAG,cAAc,EAAE,CACnB,IAAA,GACA,EAAe,GACnB,GAAI,EACF,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAM,EAAI,WACZ,EAAO,GACP,EAAG,aAAa,EAAI,CACtB,EAAO,EAAI,KAEX,EAAG,iBAAiB,EAAI,EACxB,EAAG,aAAa,EAAI,WAAW,GAE/B,EAAO,EAAI,WAAW,MAEpB,IAAS,EAAQ,gBACnB,EAAe,IAIrB,OAAO,GACP,EAEA,GAAS,YACX,EAAW,EAAS,OAAQ,GAAM,CAChC,GAAI,EAAE,qBACC,IAAM,KAAU,EAAE,gBACrB,GAAI,EAAO,QAAU,EAAG,WAAW,oBAC5B,IAAM,KAAQ,EAAO,MACxB,GACE,EAAG,aAAa,EAAK,WAAW,EAChC,EAAK,WAAW,OAAS,EAAQ,UAEjC,MAAO,IAMjB,MAAO,IACP,EAEA,GAAS,eACX,EAAW,EAAS,OAAQ,GAAM,CAChC,GAAI,EAAE,qBACC,IAAM,KAAU,EAAE,gBACrB,GAAI,EAAO,QAAU,EAAG,WAAW,uBAC5B,IAAM,KAAQ,EAAO,MACxB,GACE,EAAG,aAAa,EAAK,WAAW,EAChC,EAAK,WAAW,OAAS,EAAQ,aAEjC,MAAO,IAMjB,MAAO,IACP,EAEA,GAAS,eAAgB,CAC3B,IAAI,EACJ,OAAQ,EAAQ,eAAhB,CACE,IAAK,SACH,EAAa,EAAG,WAAW,cAC3B,MACF,IAAK,UACH,EAAa,EAAG,WAAW,eAC3B,MACF,IAAK,WACH,EAAa,EAAG,WAAW,gBAC3B,MACF,QACE,MAAU,MACR,YAAY,EAAQ,eAAe,0BACpC,CAEL,EAAW,EAAS,OAAQ,IACR,EAAG,iBAAiB,EAAE,CAAG,EAAG,aAAa,EAAE,CAAG,IAAA,KAC9C,KAAM,GAAmB,EAAE,OAAS,EAAW,CACjE,CAGJ,MAAO,CACL,KAAM,eACN,QAAS,EACT,UACD,CC3HH,SAAgB,EACd,EACA,EACU,CACV,IAAM,EAAyB,EAAE,CAC3B,EAAkB,EAAQ,oBAAoB,CAE9C,EAAS,GAAkB,CAC/B,GAAI,EAAG,oBAAoB,EAAK,CAAE,CAChC,IAAM,EAAmB,EAAK,gBAAqC,KAC7D,EAAW,EAAG,kBAClB,EACA,EAAW,SACX,EACA,EAAG,IACJ,CACG,EAAS,gBAAgB,mBACtB,EAAS,eAAe,yBAC3B,EAAa,KAAK,EAAS,eAAe,iBAAiB,UAGtD,EAAG,oBAAoB,EAAK,EAAI,EAAK,gBAAiB,CAC/D,IAAM,EAAmB,EAAK,gBAAqC,KAC7D,EAAW,EAAG,kBAClB,EACA,EAAW,SACX,EACA,EAAG,IACJ,CACG,EAAS,gBAAgB,mBACtB,EAAS,eAAe,yBAC3B,EAAa,KAAK,EAAS,eAAe,iBAAiB,EAIjE,EAAG,aAAa,EAAM,EAAM,EAI9B,OADA,EAAM,EAAW,CACV,ECrCT,SAAgB,EACd,EACA,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAE/B,IAAK,IAAM,KAAQ,EAAQ,MAAO,CAGhC,IAAM,EAFe,EAAoB,EAAM,EAAQ,QAE/B,CAAa,KAClC,GACC,EAAQ,SAAS,IAAI,EAAa,GAAG,EACrC,EAAQ,SAAS,KAAK,EAAa,IAAI,CAC1C,CAEG,GAAS,EACX,EAAW,KACT,QAAQ,EAAK,SAAS,uBAAuB,EAAa,qBAC3D,CACQ,CAAC,GAAS,CAAC,GACpB,EAAW,KACT,QAAQ,EAAK,SAAS,+BAA+B,EAAa,kBACnE,CAIL,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CC9BH,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CACzB,EAAoB,IAAI,IAC5B,EAAQ,MAAM,IAAK,GAAM,EAAE,SAAS,CACrC,CACK,EAAQ,IAAI,IAElB,IAAK,IAAM,KAAQ,EAAQ,MAAO,CAChC,IAAM,EAAW,EAAK,SAChB,EAAe,EAAoB,EAAM,EAAQ,QAAQ,CAAC,OAC7D,GAAM,EAAkB,IAAI,EAAE,CAChC,CAED,EAAM,IAAI,EAAU,EAAa,CAGnC,IAAM,EAAU,IAAI,IACd,EAAW,IAAI,IACf,EAAqB,EAAE,CAEvB,GAAgB,EAAc,IAAmB,CACrD,GAAI,EAAS,IAAI,EAAK,CAAE,CACtB,IAAM,EAAkB,EAAK,QAAQ,EAAK,CACpC,EAAW,CAAC,GAAG,EAAK,MAAM,EAAgB,CAAE,EAAK,CAAC,KAAK,KAAK,CAIlE,OAHK,EAAO,KAAM,GAAM,EAAE,KAAK,KAAK,GAAK,EAAS,EAChD,EAAO,KAAK,CAAC,GAAG,EAAK,MAAM,EAAgB,CAAE,EAAK,CAAC,CAE9C,GAGT,GAAI,EAAQ,IAAI,EAAK,CAAE,MAAO,GAE9B,EAAQ,IAAI,EAAK,CACjB,EAAS,IAAI,EAAK,CAClB,EAAK,KAAK,EAAK,CAEf,IAAM,EAAY,EAAM,IAAI,EAAK,EAAI,EAAE,CACvC,IAAK,IAAM,KAAY,EACrB,EAAa,EAAU,EAAK,CAK9B,OAFA,EAAS,OAAO,EAAK,CACrB,EAAK,KAAK,CACH,IAGT,IAAK,IAAM,KAAQ,EAAM,MAAM,CACxB,EAAQ,IAAI,EAAK,EACpB,EAAa,EAAM,EAAE,CAAC,CAI1B,GAAI,GAAS,EAAO,SAAW,EAC7B,EAAW,KAAK,gDAAgD,SACvD,CAAC,GAAS,EAAO,OAAS,EACnC,IAAK,IAAM,KAAS,EAClB,EAAW,KAAK,mBAAmB,EAAM,KAAK,OAAO,GAAG,CAI5D,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CChEH,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,MACP,GAAM,EAAE,SACR,GAAS,CACR,IAAI,EAAa,EACX,EAAS,GAAkB,EAE7B,EAAG,sBAAsB,EAAK,EAC9B,EAAG,oBAAoB,EAAK,EAC5B,EAAG,gBAAgB,EAAK,EACxB,EAAG,qBAAqB,EAAK,IAE7B,GAAc,EAA8B,EAAK,EAEnD,EAAG,aAAa,EAAM,EAAM,EAG9B,OADA,EAAM,EAAK,CACJ,GAET,OACA,EACA,EACD,CC7BH,SAAgB,EACd,EACA,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAQ,EAAQ,MAAO,CAChC,IAAI,EAAoB,EAExB,EAAG,aAAa,EAAO,GAAS,CAC1B,EAAG,sBAAsB,EAAK,GACd,EAAG,iBAAiB,EAAK,CACvC,EAAG,aAAa,EAAK,CACrB,IAAA,KACW,KAAM,GAAM,EAAE,OAAS,EAAG,WAAW,cAAc,EAChE,KAGJ,CAEF,IAAM,EAAU,EAAoB,EAEhC,GAAS,EACX,EAAW,KACT,QAAQ,EAAK,SAAS,OAAO,EAAkB,oDAAoD,EAAI,qBACxG,CACQ,CAAC,GAAS,GACnB,EAAW,KACT,QAAQ,EAAK,SAAS,OAAO,EAAkB,oDAAoD,EAAI,GACxG,CAGL,MAAO,CACL,KAAM,EAAQ,EAAW,OAAS,EAAI,EAAW,SAAW,EAC5D,YACE,EAAW,KAAK;EAAK,GACpB,EACG,0EACA,IACP,CCxCH,SAAgB,EAA8B,EAAuB,CACnE,IAAI,EAAY,EACZ,EAAW,EACT,EAAkB,IAAI,IACtB,EAAiB,IAAI,IACvB,EAAc,EAEZ,EAAa,EAAK,eAAe,CACvC,GAAI,EAAY,CACd,IAAM,EAAQ,EAAW,8BAA8B,EAAK,UAAU,CAAC,CAEvE,EADY,EAAW,8BAA8B,EAAK,QAAQ,CACpD,CAAI,KAAO,EAAM,KAAO,EAGxC,IAAM,EAAS,GAAe,CAE1B,EAAG,mBAAmB,EAAE,EACxB,EAAG,wBAAwB,EAAE,EAC7B,EAAG,yBAAyB,EAAE,EAE9B,IACA,EAAgB,IAAI,EAAE,KAAK,GAClB,EAAG,aAAa,EAAE,EAAI,EAAG,oBAAoB,EAAE,IACxD,IACA,EAAe,IAAI,EAAE,QAAQ,EAAW,CAAC,EAE3C,EAAG,aAAa,EAAG,EAAM,EAG3B,EAAM,EAAK,CAEX,IAAM,EAAI,EAAY,EAChB,EAAI,EAAgB,KAAO,EAAe,KAC1C,EAAI,IAAM,EAAI,EAAI,EAAI,KAAK,KAAK,EAAE,CAClC,EAAK,EAA8B,EAAK,CAQ9C,OANW,KAAK,IACd,GACE,IAAM,IAAM,KAAK,IAAI,GAAK,EAAE,CAAG,IAAO,EAAK,KAAO,KAAK,IAAI,EAAY,EACvE,IACA,IAEG,CC3CT,SAAgB,EACd,EACA,EACA,EACA,EACA,EACA,EACA,CACA,OAAO,EAAY,EAAO,EAAQ,GAAS,CACzC,IAAM,EAAO,EAAQ,EAAK,CACpB,EAAK,EAAM,EAAK,CAChB,EAAa,EAAK,EAClB,EAAO,GAAG,EAAM,GAAG,GAAQ,cAEjC,MAAO,CACL,OAAQ,CAAC,EACT,YAAa,GAAG,EAAK,kCAAkC,EAAG,QAAQ,EAAE,CAAC,qCAAqC,EAAI,GAC9G,eAAgB,GAAG,EAAK,kCAAkC,EAAG,QAAQ,EAAE,CAAC,qCAAqC,EAAI,qBAClH,EACD,CChBJ,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,MACP,GAAM,EAAE,SACT,EACA,OACA,EACA,EACD,CCbH,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,MACP,GAAM,EAAE,SACT,OACA,EACA,EACD,CCZH,SAAgB,EACd,EACA,EACA,EACiB,CACjB,IAAI,EAAW,EASf,GAPI,GAAS,WACX,EAAW,EAAS,OACjB,GACC,EAAK,SAAS,SAAS,IAAI,EAAQ,SAAS,GAAG,EAC/C,EAAK,SAAS,SAAS,KAAK,EAAQ,SAAS,IAAI,CACpD,EAEC,GAAS,iBAAkB,CAC7B,IAAM,EACJ,OAAO,EAAQ,kBAAqB,SAChC,IAAI,OAAO,EAAQ,iBAAiB,CACpC,EAAQ,iBACd,EAAW,EAAS,OAAQ,GAAS,EAAM,KAAK,EAAK,SAAS,CAAC,CAGjE,MAAO,CACL,KAAM,cACN,MAAO,EACP,UACD,CCzBH,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAQ,UAAW,CACjC,IAAM,EACJ,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,qBAC9C,EAAU,CAAC,CAAC,EAAE,KAEhB,GAAS,EACX,EAAW,KACT,YAAY,EAAK,iDAClB,CACQ,CAAC,GAAS,CAAC,GACpB,EAAW,KACT,YAAY,EAAK,wDAClB,CAGL,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCrBH,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,UACP,GAAO,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,IAAA,GAC1D,EACA,WACA,EACA,EACD,CCZH,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,UACP,GAAO,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,IAAA,GAC1D,EACA,WACA,EACA,EACD,CCbH,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,UACP,GAAO,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,IAAA,GAC1D,WACA,EACA,EACD,CCXH,SAAgB,EACd,EACA,EACY,CACZ,OAAO,EACL,EAAQ,UACP,GAAO,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,IAAA,GAC1D,WACA,EACD,CCTH,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAO,EACL,EAAQ,UACP,GAAO,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,IAAA,GAC1D,WACA,EACA,EACD,CCbH,SAAgB,EACd,EACA,EACA,EACqB,CACrB,IAAI,EAAW,EAiBf,GAfI,GAAS,WACX,EAAW,EAAS,OAAQ,GAAM,CAChC,IAAM,EAAa,EAAE,cACjB,EAAE,eAAe,CACjB,EAAE,OACA,EAAG,oBAAoB,EAAE,CACzB,IAAA,GAEN,OADK,EAEH,EAAW,SAAS,SAAS,IAAI,EAAQ,SAAS,GAAG,EACrD,EAAW,SAAS,SAAS,KAAK,EAAQ,SAAS,IAAI,CAHjC,IAKxB,EAGA,GAAS,iBAAkB,CAC7B,IAAM,EACJ,OAAO,EAAQ,kBAAqB,SAChC,IAAI,OAAO,EAAQ,iBAAiB,CACpC,EAAQ,iBACd,EAAW,EAAS,OAAQ,GACnB,EAAE,MAAQ,EAAG,aAAa,EAAE,KAAK,EAAI,EAAM,KAAK,EAAE,KAAK,KAAK,CACnE,CASJ,OANI,GAAS,aACX,EAAW,EAAS,OAAQ,GACnB,EAAG,aAAa,EAAE,OAAO,CAChC,EAGG,CACL,KAAM,kBACN,UAAW,EACX,UACD,CC1CH,SAAgB,EACd,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAa,EAAK,WAC3B,EAAW,KAAK,GAAG,EAAU,EAAK,MAAM,CAAC,CAE3C,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCVH,SAAgB,EACd,EACA,EACyB,CACzB,MAAO,CACL,KAAM,sBACN,QACA,OAAQ,IAAI,IACZ,WAAY,EAAE,CACd,UACD,CCXH,SAAgB,EACd,EACA,EACA,EACyB,CAEzB,OADA,EAAK,OAAO,IAAI,EAAM,EAAc,CAC7B,ECNT,SAAgB,EACd,EACA,EACU,CACV,IAAM,EAAyB,EAAE,CAC3B,EAAkB,EAAQ,oBAAoB,CAE9C,EAAS,GAAkB,CAC/B,GAAI,EAAG,oBAAoB,EAAK,CAAE,CAChC,IAAM,EAAmB,EAAK,gBAAqC,KAC7D,EAAW,EAAG,kBAClB,EACA,EAAW,SACX,EACA,EAAG,IACJ,CAEC,EAAS,gBAAgB,kBACzB,CAAC,EAAS,eAAe,yBAEzB,EAAa,KAAK,EAAS,eAAe,iBAAiB,SAEpD,EAAG,oBAAoB,EAAK,EAAI,EAAK,gBAAiB,CAC/D,IAAM,EAAmB,EAAK,gBAAqC,KAC7D,EAAW,EAAG,kBAClB,EACA,EAAW,SACX,EACA,EAAG,IACJ,CAEC,EAAS,gBAAgB,kBACzB,CAAC,EAAS,eAAe,yBAEzB,EAAa,KAAK,EAAS,eAAe,iBAAiB,CAG/D,EAAG,aAAa,EAAM,EAAM,EAI9B,OADA,EAAM,EAAW,CACV,ECxCT,SAAgB,EACd,EACA,EACyB,CACzB,GAAI,CAAC,EAAK,OAAO,IAAI,EAAY,CAC/B,MAAU,MAAM,SAAS,EAAY,iBAAiB,CA8BxD,OA3BA,EAAK,WAAW,KAAM,GAAU,CAC9B,IAAM,EAAuB,EAAE,CAEzB,EAAgB,EAAK,OAAO,IAAI,EAAY,CAElD,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,SAEpB,CAAC,EAAS,SAAS,IAAI,EAAc,GAAG,EACxC,CAAC,EAAS,SAAS,KAAK,EAAc,IAAI,EAErB,EAAqB,EAAM,EAAK,QAC/B,CAAa,KAChC,GACC,EAAI,SAAS,IAAI,EAAc,GAAG,EAClC,EAAI,SAAS,KAAK,EAAc,IAAI,CAEpC,EACF,EAAW,KACT,QAAQ,EAAS,kBAAkB,EAAY,oBAChD,CAIP,OAAO,GACP,CAEK,ECnCT,SAAgB,EACd,EACA,EACA,EACyB,CACzB,GAAI,CAAC,EAAK,OAAO,IAAI,EAAY,CAC/B,MAAU,MAAM,SAAS,EAAY,iBAAiB,CAqCxD,OAlCA,EAAK,WAAW,KAAM,GAAU,CAC9B,IAAM,EAAuB,EAAE,CAEzB,EAAgB,EAAK,OAAO,IAAI,EAAY,CAE5C,EAAkB,EAAc,IAAK,GAAM,EAAK,OAAO,IAAI,EAAE,CAAE,CAErE,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,SAChB,EAAmB,EAAgB,KACtC,GAAM,EAAS,SAAS,IAAI,EAAE,GAAG,EAAI,EAAS,SAAS,KAAK,EAAE,IAAI,CACpE,CAGC,CAAC,EAAS,SAAS,IAAI,EAAc,GAAG,EACxC,CAAC,EAAS,SAAS,KAAK,EAAc,IAAI,EAC1C,CAAC,GAEoB,EAAqB,EAAM,EAAK,QAC/B,CAAa,KAChC,GACC,EAAI,SAAS,IAAI,EAAc,GAAG,EAClC,EAAI,SAAS,KAAK,EAAc,IAAI,CAEpC,EACF,EAAW,KACT,QAAQ,EAAS,kBAAkB,EAAY,YAAY,EAAc,KAAK,KAAK,CAAC,eACrF,CAIP,OAAO,GACP,CAEK,EC3CT,SAAgB,EACd,EACA,EACA,EACqB,CACrB,IAAI,EAAW,EAiBf,GAfI,GAAS,WACX,EAAW,EAAS,OAAQ,GAAM,CAChC,IAAM,EAAa,EAAE,cACjB,EAAE,eAAe,CACjB,EAAE,OACA,EAAG,oBAAoB,EAAE,CACzB,IAAA,GAEN,OADK,EAEH,EAAW,SAAS,SAAS,IAAI,EAAQ,SAAS,GAAG,EACrD,EAAW,SAAS,SAAS,KAAK,EAAQ,SAAS,IAAI,CAHjC,IAKxB,EAGA,GAAS,iBAAkB,CAC7B,IAAM,EACJ,OAAO,EAAQ,kBAAqB,SAChC,IAAI,OAAO,EAAQ,iBAAiB,CACpC,EAAQ,iBACd,EAAW,EAAS,OAAQ,GACnB,EAAG,aAAa,EAAE,KAAK,EAAI,EAAM,KAAK,EAAE,KAAK,KAAK,CACzD,CAGJ,MAAO,CACL,KAAM,kBACN,WAAY,EACZ,UACD,CCpCH,SAAgB,EACd,EACA,EACA,EACkB,CAElB,IAAM,EADU,EAAQ,QAAQ,qBAAsB,OACrC,CAAQ,QAAQ,MAAO,cAAc,CAChD,EAAe,IAAI,OAAO,EAAS,CAEnC,EAAW,IAAI,IACf,EAAa,IAAI,IAEvB,IAAK,IAAM,KAAM,EAAa,CAC5B,IAAM,EAAQ,EAAG,SAAS,MAAM,EAAa,CAC7C,GAAI,IAAQ,GAAI,CACd,IAAM,EAAU,EAAM,GACtB,EAAS,IAAI,EAAQ,CAChB,EAAW,IAAI,EAAQ,EAC1B,EAAW,IAAI,EAAS,EAAE,CAAC,CAE7B,EAAW,IAAI,EAAQ,EAAE,KAAK,EAAG,EAIrC,MAAO,CACL,KAAM,eACN,eACA,WACA,aACA,UACD,CChBH,SAAgB,GAAa,EAAyC,EAAE,CAAE,CACxE,IAAI,EAAsC,EAAE,CACtC,EACJ,EAAQ,kBACR,EAAG,eAAe,QAAQ,KAAK,CAAE,EAAG,IAAI,WAAY,gBAAgB,CAElE,EAEJ,GAAI,EAAY,CACd,IAAM,EAAa,EAAG,eAAe,EAAY,EAAG,IAAI,SAAS,CAC3D,EAAoB,EAAG,2BAC3B,EAAW,OACX,EAAG,KAAA,EAAA,EAAA,SACK,EAAW,CACnB,IAAA,GACA,EACA,IAAA,GACA,CACE,CACE,UAAW,OACX,eAAgB,GAChB,WAAY,EAAG,WAAW,GAC3B,CACD,CACE,UAAW,UACX,eAAgB,GAChB,WAAY,EAAG,WAAW,GAC3B,CACF,CACF,CACD,EAAkB,EAAkB,QAEpC,IAAM,EAAO,EAAG,mBAAmB,EAAgB,CAC7C,EAAwB,EAAK,cAG/B,EACJ,GAAI,CACF,EAAc,QAAQ,oBAAoB,MAC/B,EAIb,EAAK,eACH,EACA,EACA,EACA,IACG,CACH,GAAI,EAAS,SAAS,OAAO,CAAE,CAC7B,IAAM,EAAU,EAAG,IAAI,SAAS,EAAS,CACzC,GAAI,EAAS,CACX,IAAI,EAAgB,GACpB,GAAI,EAAa,CACf,IAAM,EAAS,EAAY,MAAM,EAAQ,CACnC,EAAS,EAAO,WAAW,OAC3B,EAAc,EAAO,WAAW,YAClC,IAAQ,GAAiB,GAAG,EAAO,QAAQ,KAC3C,IAAa,GAAiB,GAAG,EAAY,QAAQ,SACpD,CACL,IAAM,EAAQ,EAAQ,MAAM,gCAAgC,CACxD,IAAO,EAAgB,EAAM,IAEnC,OAAO,EAAG,iBACR,EACA,EACA,EACA,GACA,EAAG,WAAW,GACf,EAIL,GAAI,EAAS,SAAS,UAAU,CAAE,CAChC,IAAM,EAAU,EAAG,IAAI,SAAS,EAAS,CACzC,GAAI,EAAS,CACX,IAAI,EAAgB,GACd,EAAQ,EAAQ,MAAM,gCAAgC,CAE5D,OADI,IAAO,EAAgB,EAAM,IAC1B,EAAG,iBACR,EACA,EACA,EACA,GACA,EAAG,WAAW,GACf,EAIL,OAAO,EACL,EACA,EACA,EACA,EACD,EAGH,EAAU,EAAG,cAAc,CACzB,UAAW,EAAkB,UAC7B,QAAS,EACH,OACP,CAAC,CAGF,EAAQ,gBAAgB,MAExB,MAAU,MAAM,+BAA+B,CAGjD,IAAM,MACJ,EACG,gBAAgB,CAChB,OACE,GAAO,CAAC,EAAG,mBAAqB,CAAC,EAAG,SAAS,SAAS,eAAe,CACvE,CAEL,MAAO,CACL,SAAW,GACF,EAAY,GAAgB,CAAE,EAAS,EAAa,CAG7D,WAAa,GAAqC,CAChD,IAAM,EAAoC,EAAE,CAC5C,IAAK,IAAM,KAAM,GAAgB,CAAE,CACjC,IAAM,EAAS,GAAkB,CAC3B,EAAG,mBAAmB,EAAK,EAC7B,EAAW,KAAK,EAAK,CAEvB,EAAG,aAAa,EAAM,EAAM,EAE9B,EAAM,EAAG,CAEX,OAAO,EAAc,EAAY,EAAS,EAAa,EAGzD,wBAA2B,CACzB,IAAI,EAAO,EAA0B,GAAgB,CAAE,EAAQ,CACzD,EAAM,CACV,OAAQ,EAAc,KACpB,EAAO,EAAM,EAAM,EAAM,EAAc,CAChC,GAET,WAAa,IACJ,CACL,mCACE,EAAO,EAAmC,EAAM,EAAK,CAC9C,GAET,wBAAyB,GAAG,KAC1B,EAAO,EAA4B,EAAM,EAAM,EAAc,CACtD,GAEV,EAEH,UAAa,EAAyB,EAAK,CAC3C,IAAI,MAAO,CACT,OAAO,GAEV,CACD,OAAO,GAGT,aAAe,GAAwC,CACrD,IAAM,EAA6C,EAAE,CACrD,IAAK,IAAM,KAAM,GAAgB,CAAE,CACjC,IAAM,EAAS,GAAkB,EAE7B,EAAG,sBAAsB,EAAK,EAC9B,EAAG,oBAAoB,EAAK,EAC5B,EAAG,gBAAgB,EAAK,GAExB,EAAa,KAAK,EAAK,CAEzB,EAAG,aAAa,EAAM,EAAM,EAE9B,EAAM,EAAG,CAEX,OAAO,EAAgB,EAAc,EAAS,EAAa,EAG7D,cAAgB,GAAwC,CACtD,IAAM,EAA0C,EAAE,CAClD,IAAK,IAAM,KAAM,GAAgB,CAAE,CACjC,IAAM,EAAS,GAAkB,CAC3B,EAAG,sBAAsB,EAAK,EAChC,EAAc,KAAK,EAAK,CAE1B,EAAG,aAAa,EAAM,EAAM,EAE9B,EAAM,EAAG,CAEX,OAAO,EAAiB,EAAe,EAAS,EAAa,EAG/D,UAAY,GACH,EAAa,GAAgB,CAAE,EAAS,EAAQ,CAE1D,CClNH,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAQ,WAAY,CAClC,IAAM,EAAO,EAAG,aAAa,EAAE,KAAK,CAAG,EAAE,KAAK,KAAO,qBAE/C,GADY,EAAG,iBAAiB,EAAE,CAAG,EAAG,aAAa,EAAE,CAAG,IAAA,KACrC,KACxB,GAAmB,EAAE,OAAS,EAAG,WAAW,gBAC9C,CAEG,GAAS,EACX,EAAW,KAAK,YAAY,EAAK,oCAAoC,CAC5D,CAAC,GAAS,CAAC,GACpB,EAAW,KAAK,YAAY,EAAK,qCAAqC,CAG1E,MAAO,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCrBH,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAkC,IAAI,IAC5C,IAAK,IAAM,KAAS,EAAQ,SAC1B,EAAM,IAAI,EAAO,IAAI,IAAM,CAG7B,IAAK,GAAM,CAAC,EAAS,KAAU,EAAQ,WAAW,SAAS,CACzD,IAAK,IAAM,KAAM,EACf,EAAG,aAAa,EAAK,GAAS,CAC5B,GACE,EAAG,oBAAoB,EAAK,EAC5B,EAAK,iBACL,EAAG,gBAAgB,EAAK,gBAAgB,CACxC,CACA,IAAM,EAAa,EAAK,gBAAgB,KAClC,EAAW,EAAG,kBAClB,EACA,EAAG,SACH,EAAQ,QAAQ,oBAAoB,CACpC,EAAG,IACJ,CACD,GAAI,EAAS,gBAAgB,iBAAkB,CAC7C,IAAM,EAAc,EAAS,eAAe,iBAAiB,MAC3D,EAAQ,aACT,CACD,GAAI,IAAc,GAAI,CACpB,IAAM,EAAc,EAAY,GAE9B,IAAgB,GAChB,EAAQ,SAAS,IAAI,EAAY,EAEjC,EAAM,IAAI,EAAQ,EAAE,IAAI,EAAY,KAK5C,CAIN,IAAM,EAAU,IAAI,IACd,EAAiB,IAAI,IACrB,EAAuB,EAAE,CAEzB,GAAO,EAAc,IAA4B,CACrD,EAAQ,IAAI,EAAK,CACjB,EAAe,IAAI,EAAK,CAExB,IAAK,IAAM,KAAY,EAAM,IAAI,EAAK,EAAI,EAAE,CAC1C,GAAI,CAAC,EAAQ,IAAI,EAAS,KACpB,EAAI,EAAU,CAAC,GAAG,EAAM,EAAS,CAAC,CAAE,MAAO,WACtC,EAAe,IAAI,EAAS,CAIrC,OAHA,EAAW,KACT,kCAAkC,EAAK,KAAK,OAAO,CAAC,MAAM,IAC3D,CACM,GAKX,OADA,EAAe,OAAO,EAAK,CACpB,IAGT,IAAK,IAAM,KAAS,EAAQ,SACrB,EAAQ,IAAI,EAAM,EACrB,EAAI,EAAO,CAAC,EAAM,CAAC,CAarB,OATE,EACK,CACL,KAAM,EAAW,OAAS,EAC1B,YACE,EAAW,OAAS,EAChB,GACA,iDACP,CAEM,CACL,KAAM,EAAW,SAAW,EAC5B,YAAe,EAAW,KAAK;EAAK,CACrC,CCpFL,SAAgB,EACd,EACA,EACA,EACY,CACZ,IAAM,EAAuB,EAAE,CAEzB,EAAQ,IAAI,IACZ,EAAQ,IAAI,IAElB,IAAK,IAAM,KAAS,EAAQ,SAC1B,EAAM,IAAI,EAAO,IAAI,IAAM,CAC3B,EAAM,IAAI,EAAO,IAAI,IAAM,CAG7B,IAAK,GAAM,CAAC,EAAS,KAAU,EAAQ,WAAW,SAAS,CACzD,IAAK,IAAM,KAAM,EACf,EAAG,aAAa,EAAK,GAAS,CAC5B,GACE,EAAG,oBAAoB,EAAK,EAC5B,EAAK,iBACL,EAAG,gBAAgB,EAAK,gBAAgB,CACxC,CACA,IAAM,EAAa,EAAK,gBAAgB,KAClC,EAAW,EAAG,kBAClB,EACA,EAAG,SACH,EAAQ,QAAQ,oBAAoB,CACpC,EAAG,IACJ,CACD,GAAI,EAAS,gBAAgB,iBAAkB,CAC7C,IAAM,EAAc,EAAS,eAAe,iBAAiB,MAC3D,EAAQ,aACT,CACD,GAAI,IAAc,GAAI,CACpB,IAAM,EAAc,EAAY,GAE9B,IAAgB,GAChB,EAAQ,SAAS,IAAI,EAAY,GAEjC,EAAM,IAAI,EAAQ,EAAE,IAAI,EAAY,CACpC,EAAM,IAAI,EAAY,EAAE,IAAI,EAAQ,MAK5C,CAIN,IAAK,IAAM,KAAW,EAAQ,SAAU,CACtC,IAAM,EAAK,EAAM,IAAI,EAAQ,EAAE,KACzB,EAAK,EAAM,IAAI,EAAQ,EAAE,KAGzB,EAAQ,EAAQ,WAAW,IAAI,EAAQ,CACzC,EAAK,EACL,EAAK,EAET,IAAK,IAAM,KAAM,EAAO,CACtB,IAAM,EAAS,GAAkB,CAC3B,EAAG,mBAAmB,EAAK,EAC7B,KACkB,EAAG,iBAAiB,EAAK,CACvC,EAAG,aAAa,EAAK,CACrB,IAAA,KAES,KAAM,GAAM,EAAE,OAAS,EAAG,WAAW,gBAAgB,EAEhE,KAEO,EAAG,uBAAuB,EAAK,GACxC,IACA,KAEF,EAAG,aAAa,EAAM,EAAM,EAE9B,EAAM,EAAG,CAGX,IAAM,EAAI,EAAK,IAAO,EAAI,EAAI,GAAM,EAAK,GACnC,EAAI,IAAO,EAAI,EAAI,EAAK,EAExB,EAAI,KAAK,IAAI,EAAI,EAAI,EAAE,CACvB,EAAU,EAAI,EAEhB,GAAS,EACX,EAAW,KACT,SAAS,EAAQ,4CAA4C,EAAE,QAAQ,EAAE,CAAC,iCAAiC,EAAI,qBAChH,CACQ,CAAC,GAAS,GACnB,EAAW,KACT,SAAS,EAAQ,4CAA4C,EAAE,QAAQ,EAAE,CAAC,iCAAiC,EAAI,GAChH,CAIL,MAAO,CACL,KAAM,EAAQ,EAAW,OAAS,EAAI,EAAW,SAAW,EAC5D,YACE,EAAW,KAAK;EAAK,GACpB,EACG,oFACA,IACP,CChFH,SAAgB,IAAgB,CAC9B,EAAA,OAAO,OAAO,CAEZ,OAAO,EAAe,CACpB,IAAI,EAEJ,AAGE,EAHE,GAAU,MAAQ,EAAS,KAAK,OAAS,sBAClC,EAAyB,EAAS,KAAK,CAEvC,EAGX,GAAM,CAAE,OAAM,WAAY,EAC1B,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,EAC3B,QAAS,MAAa,gCAAoC,GAAS,CACpE,EAGH,iBAAiB,EAAuB,EAAgB,CACtD,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,EAAS,EAAyB,EAAU,EAAQ,KAAK,MAAM,MAE/D,MAAU,MACR,6CAA6C,EAAS,OACvD,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,eAAe,EAAuB,EAAkB,CACtD,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,EAAS,EAAuB,EAAU,EAAU,KAAK,MAAM,SACtD,EAAS,OAAS,kBAC3B,EAAS,EAA0B,EAAU,EAAU,KAAK,MAAM,MAElE,MAAU,MACR,2CAA2C,EAAS,OACrD,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,cAAc,EAAuB,EAAmB,CACtD,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,EAAS,EAAsB,EAAU,EAAW,KAAK,MAAM,MAE/D,MAAU,MACR,0CAA0C,EAAS,OACpD,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,qBAAqB,EAAuB,EAAuB,CACjE,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,EAAS,EACP,EACA,EACA,KAAK,MACN,MAED,MAAU,MACR,iDAAiD,EAAS,OAC3D,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,yBAAyB,EAAuB,CAC9C,IAAI,EACJ,GAAI,EAAS,OAAS,kBACpB,EAAS,EAAoC,EAAU,KAAK,MAAM,MAElE,MAAU,MACR,qDAAqD,EAAS,OAC/D,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,aAAa,EAAuB,CAClC,IAAI,EACJ,GAAI,EAAS,OAAS,kBACpB,EAAS,EAAwB,EAAU,KAAK,MAAM,MAEtD,MAAU,MACR,yCAAyC,EAAS,OACnD,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,wBAAwB,EAAuB,EAAgB,CAC7D,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,EAAS,EAA2B,EAAU,EAAQ,KAAK,MAAM,MAEjE,MAAU,MACR,oDAAoD,EAAS,OAC9D,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,iBAAiB,EAAuB,CACtC,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,EAAS,EAAwB,EAAU,KAAK,MAAM,SAC7C,EAAS,OAAS,eAC3B,EAAS,EAAyB,EAAU,KAAK,MAAM,MAEvD,MAAU,MACR,6CAA6C,EAAS,OACvD,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,mBAAmB,EAAuB,EAA0B,CAClE,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,EAAS,EAA0B,EAAU,EAAS,KAAK,MAAM,SACxD,EAAS,OAAS,eAC3B,EAAS,EAA2B,EAAU,EAAS,KAAK,MAAM,SACzD,EAAS,OAAS,kBAC3B,EAAS,EAA8B,EAAU,EAAS,KAAK,MAAM,MAErE,MAAU,MACR,+CAA+C,EAAS,OACzD,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,8BAA8B,EAAuB,EAAa,CAChE,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,EAAS,EACP,EACA,EACA,KAAK,MACN,SACQ,EAAS,OAAS,eAC3B,EAAS,EACP,EACA,EACA,KAAK,MACN,SACQ,EAAS,OAAS,kBAC3B,EAAS,EACP,EACA,EACA,KAAK,MACN,MAED,MAAU,MACR,0DAA0D,EAAS,OACpE,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,8BAA8B,EAAuB,EAAa,CAChE,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,EAAS,EACP,EACA,EACA,KAAK,MACN,SACQ,EAAS,OAAS,kBAC3B,EAAS,EACP,EACA,EACA,KAAK,MACN,MAED,MAAU,MACR,0DAA0D,EAAS,OACpE,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,kCAAkC,EAAuB,EAAa,CACpE,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,EAAS,EACP,EACA,EACA,KAAK,MACN,MAED,MAAU,MACR,8DAA8D,EAAS,OACxE,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,2BAA2B,EAAuB,CAChD,IAAI,EACJ,GAAI,EAAS,OAAS,kBACpB,EAAS,EAAsC,EAAU,KAAK,MAAM,SAC3D,EAAS,OAAS,eAC3B,EAAS,EAAmC,EAAU,KAAK,MAAM,MAEjE,MAAU,MACR,uDAAuD,EAAS,OACjE,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAGH,2BAA2B,EAAuB,EAAa,CAC7D,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,EAAS,EAAkC,EAAU,EAAK,KAAK,MAAM,MAErE,MAAU,MACR,uDAAuD,EAAS,OACjE,CAEH,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,QACjB,EAEJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/matchers/index.ts"],"sourcesContent":["import {\n checkDependOnExternalModule,\n checkDependOnFilesInFolder,\n checkLayeredArchitecture,\n classCheckExtendClass,\n classCheckHaveMaxCyclomaticComplexity,\n classCheckHaveModifier,\n classCheckHaveNameMatchingFileName,\n classCheckImplementInterface,\n classCheckMatchNamePattern,\n classCheckResideInFolder,\n fileCheckBeFreeOfCycles,\n fileCheckHaveMaxCyclomaticComplexity,\n fileCheckHaveMaxExportedFunctions,\n fileCheckHaveMinMaintainabilityIndex,\n fileCheckMatchNamePattern,\n functionCheckHaveExplicitReturnType,\n functionCheckHaveMaxCyclomaticComplexity,\n functionCheckHaveMinMaintainabilityIndex,\n functionCheckHaveModifier,\n functionCheckHaveNameMatchingFileName,\n functionCheckMatchNamePattern,\n type LocatorData,\n propertyCheckBeReadonly,\n type RuleResult,\n sliceCheckBeFreeOfCycles,\n sliceCheckHaveMaxDistanceFromMainSequence,\n} from '@archest/core';\nimport { expect } from 'vitest';\nimport type { ArchestMatchers } from './models';\n\nexport * from './models';\n\n/**\n * Registers all Archest custom matchers (e.g., `toResideInFolder`, `toHaveModifier`)\n * with the global Vitest `expect` instance.\n *\n * This function must be called exactly once before any architectural tests are run.\n * The standard way to do this is to add it to a Vitest setup file.\n *\n * @example\n * ```typescript\n * // test/setup.ts\n * import { setupMatchers } from '@archest/vitest';\n * setupMatchers();\n * ```\n */\nexport function setupMatchers() {\n expect.extend({\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n toPass(received: any) {\n let result: RuleResult;\n\n if (received?.data && received.data.type === 'LayeredArchitecture') {\n result = checkLayeredArchitecture(received.data);\n } else {\n result = received as RuleResult;\n }\n\n const { pass, message } = result;\n return {\n pass: this.isNot ? !pass : pass,\n message: pass ? () => 'Expected rule not to pass' : () => message(),\n };\n },\n\n toResideInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckResideInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toResideInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveModifier(received: LocatorData, modifier: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckHaveModifier(received, modifier, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveModifier(received, modifier, this.isNot);\n } else {\n throw new Error(\n `toHaveModifier matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toExtendClass(received: LocatorData, className: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckExtendClass(received, className, this.isNot);\n } else {\n throw new Error(\n `toExtendClass matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toImplementInterface(received: LocatorData, interfaceName: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckImplementInterface(\n received,\n interfaceName,\n this.isNot,\n );\n } else {\n throw new Error(\n `toImplementInterface matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveExplicitReturnType(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveExplicitReturnType(received, this.isNot);\n } else {\n throw new Error(\n `toHaveExplicitReturnType matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeReadonly(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'PropertyLocator') {\n result = propertyCheckBeReadonly(received, this.isNot);\n } else {\n throw new Error(\n `toBeReadonly matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toDependOnFilesInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = checkDependOnFilesInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toDependOnFilesInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toDependOnExternalModule(\n received: LocatorData,\n moduleName: string | RegExp,\n ) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = checkDependOnExternalModule(received, moduleName, this.isNot);\n } else {\n throw new Error(\n `toDependOnExternalModule matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeFreeOfCycles(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckBeFreeOfCycles(received, this.isNot);\n } else if (received.type === 'SliceLocator') {\n result = sliceCheckBeFreeOfCycles(received, this.isNot);\n } else {\n throw new Error(\n `toBeFreeOfCycles matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toMatchNamePattern(received: LocatorData, pattern: string | RegExp) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckMatchNamePattern(received, pattern, this.isNot);\n } else {\n throw new Error(\n `toMatchNamePattern matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxCyclomaticComplexity(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxCyclomaticComplexity matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMinMaintainabilityIndex(received: LocatorData, min: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMinMaintainabilityIndex matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxDistanceFromMainSequence(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'SliceLocator') {\n result = sliceCheckHaveMaxDistanceFromMainSequence(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxDistanceFromMainSequence matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveNameMatchingFileName(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveNameMatchingFileName(received, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveNameMatchingFileName(received, this.isNot);\n } else {\n throw new Error(\n `toHaveNameMatchingFileName matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxExportedFunctions(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxExportedFunctions(received, max, this.isNot);\n } else {\n throw new Error(\n `toHaveMaxExportedFunctions matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n });\n}\n\ndeclare module 'vitest' {\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n interface Assertion<T = any> extends ArchestMatchers<T> {}\n}\n"],"mappings":"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"}
|