@nielspeter/eess-mermaid 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/bridge/from-diagram.d.ts +58 -0
- package/dist/bridge/from-diagram.d.ts.map +1 -0
- package/dist/bridge/from-diagram.js +112 -0
- package/dist/bridge/from-diagram.js.map +1 -0
- package/dist/builders/class-rule-builder.d.ts +45 -0
- package/dist/builders/class-rule-builder.d.ts.map +1 -0
- package/dist/builders/class-rule-builder.js +89 -0
- package/dist/builders/class-rule-builder.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/check.d.ts +8 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +44 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +6 -0
- package/dist/cli/commands/explain.d.ts.map +1 -0
- package/dist/cli/commands/explain.js +29 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/config.d.ts +8 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +4 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +130 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/load-rules.d.ts +10 -0
- package/dist/cli/load-rules.d.ts.map +1 -0
- package/dist/cli/load-rules.js +62 -0
- package/dist/cli/load-rules.js.map +1 -0
- package/dist/cli/resolve-config.d.ts +3 -0
- package/dist/cli/resolve-config.d.ts.map +1 -0
- package/dist/cli/resolve-config.js +50 -0
- package/dist/cli/resolve-config.js.map +1 -0
- package/dist/cli/watch.d.ts +8 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +114 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/conditions/class.d.ts +11 -0
- package/dist/conditions/class.d.ts.map +1 -0
- package/dist/conditions/class.js +163 -0
- package/dist/conditions/class.js.map +1 -0
- package/dist/core/diagram.d.ts +3 -0
- package/dist/core/diagram.d.ts.map +1 -0
- package/dist/core/diagram.js +18 -0
- package/dist/core/diagram.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/project.d.ts +7 -0
- package/dist/core/project.d.ts.map +1 -0
- package/dist/core/project.js +2 -0
- package/dist/core/project.js.map +1 -0
- package/dist/core/violation.d.ts +15 -0
- package/dist/core/violation.d.ts.map +1 -0
- package/dist/core/violation.js +16 -0
- package/dist/core/violation.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/models/arch-class.d.ts +20 -0
- package/dist/models/arch-class.d.ts.map +1 -0
- package/dist/models/arch-class.js +33 -0
- package/dist/models/arch-class.js.map +1 -0
- package/dist/models/er-entity.d.ts +32 -0
- package/dist/models/er-entity.d.ts.map +1 -0
- package/dist/models/er-entity.js +37 -0
- package/dist/models/er-entity.js.map +1 -0
- package/dist/parser/generated/ast.d.ts +539 -0
- package/dist/parser/generated/ast.d.ts.map +1 -0
- package/dist/parser/generated/ast.js +443 -0
- package/dist/parser/generated/ast.js.map +1 -0
- package/dist/parser/generated/grammar.d.ts +8 -0
- package/dist/parser/generated/grammar.d.ts.map +1 -0
- package/dist/parser/generated/grammar.js +10 -0
- package/dist/parser/generated/grammar.js.map +1 -0
- package/dist/parser/generated/module.d.ts +21 -0
- package/dist/parser/generated/module.d.ts.map +1 -0
- package/dist/parser/generated/module.js +32 -0
- package/dist/parser/generated/module.js.map +1 -0
- package/dist/parser/parse-class-diagram.d.ts +7 -0
- package/dist/parser/parse-class-diagram.d.ts.map +1 -0
- package/dist/parser/parse-class-diagram.js +33 -0
- package/dist/parser/parse-class-diagram.js.map +1 -0
- package/dist/parser/parse-directives.d.ts +38 -0
- package/dist/parser/parse-directives.d.ts.map +1 -0
- package/dist/parser/parse-directives.js +96 -0
- package/dist/parser/parse-directives.js.map +1 -0
- package/dist/parser/parse-er-diagram.d.ts +4 -0
- package/dist/parser/parse-er-diagram.d.ts.map +1 -0
- package/dist/parser/parse-er-diagram.js +27 -0
- package/dist/parser/parse-er-diagram.js.map +1 -0
- package/dist/parser/validate-diagram.d.ts +11 -0
- package/dist/parser/validate-diagram.d.ts.map +1 -0
- package/dist/parser/validate-diagram.js +67 -0
- package/dist/parser/validate-diagram.js.map +1 -0
- package/dist/predicates/class.d.ts +13 -0
- package/dist/predicates/class.d.ts.map +1 -0
- package/dist/predicates/class.js +73 -0
- package/dist/predicates/class.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Niels Peter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @nielspeter/eess-mermaid
|
|
2
|
+
|
|
3
|
+
Architecture testing for **Mermaid class diagrams** — the Mermaid dialect of the [eess](../../README.md) family. _Specifications you can run._
|
|
4
|
+
|
|
5
|
+
Formerly published as `@nielspeter/mermaidunit`. Runs on the shared [`@nielspeter/eess`](../core) kernel, so it speaks the same fluent DSL as the other dialects.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -D @nielspeter/eess-mermaid
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
Parse a Mermaid class diagram and assert structural rules over its classes, stereotypes, and relationships:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { diagram, classes } from '@nielspeter/eess-mermaid'
|
|
19
|
+
|
|
20
|
+
const d = diagram('docs/architecture.mmd')
|
|
21
|
+
|
|
22
|
+
classes(d).that().haveStereotype('repository').should().haveNameEndingWith('Repository').check()
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The diagram is validated for internal consistency (valid class references, stereotypes, relationships) via the Langium grammar. Cross-validation against TypeScript code — binding a diagram to its implementation so either side drifting fails the build — is [plan 0059](../../plans/0059-cross-validation-eess-crossvalidate.md).
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
MIT
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ArchProject } from '../core/project.js';
|
|
2
|
+
export interface BridgeOptions {
|
|
3
|
+
classToFolder?: Record<string, string>;
|
|
4
|
+
stereotypeToFolder?: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export interface BridgeRuleAllowedEdge {
|
|
7
|
+
id: string;
|
|
8
|
+
kind: 'allowed-edge';
|
|
9
|
+
source: {
|
|
10
|
+
class: string;
|
|
11
|
+
folder: string;
|
|
12
|
+
stereotype?: string;
|
|
13
|
+
};
|
|
14
|
+
target: {
|
|
15
|
+
class: string;
|
|
16
|
+
folder: string;
|
|
17
|
+
stereotype?: string;
|
|
18
|
+
};
|
|
19
|
+
arrow: string;
|
|
20
|
+
because: string;
|
|
21
|
+
}
|
|
22
|
+
export interface BridgeRuleForbiddenEdge {
|
|
23
|
+
id: string;
|
|
24
|
+
kind: 'forbidden-edge';
|
|
25
|
+
source: {
|
|
26
|
+
folder: string;
|
|
27
|
+
stereotype?: string;
|
|
28
|
+
};
|
|
29
|
+
target: {
|
|
30
|
+
folder: string;
|
|
31
|
+
stereotype?: string;
|
|
32
|
+
};
|
|
33
|
+
because: string;
|
|
34
|
+
}
|
|
35
|
+
export interface BridgeRuleInheritance {
|
|
36
|
+
id: string;
|
|
37
|
+
kind: 'inheritance';
|
|
38
|
+
sub: {
|
|
39
|
+
class: string;
|
|
40
|
+
folder: string;
|
|
41
|
+
stereotype?: string;
|
|
42
|
+
};
|
|
43
|
+
sup: {
|
|
44
|
+
class: string;
|
|
45
|
+
folder: string;
|
|
46
|
+
stereotype?: string;
|
|
47
|
+
};
|
|
48
|
+
because: string;
|
|
49
|
+
}
|
|
50
|
+
export type BridgeRule = BridgeRuleAllowedEdge | BridgeRuleForbiddenEdge | BridgeRuleInheritance;
|
|
51
|
+
export interface BridgeOutput {
|
|
52
|
+
version: 1;
|
|
53
|
+
layers: Record<string, string>;
|
|
54
|
+
allowed: Array<[string, string]>;
|
|
55
|
+
rules: BridgeRule[];
|
|
56
|
+
}
|
|
57
|
+
export declare function fromDiagram(project: ArchProject, options: BridgeOptions): BridgeOutput;
|
|
58
|
+
//# sourceMappingURL=from-diagram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-diagram.d.ts","sourceRoot":"","sources":["../../src/bridge/from-diagram.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAMrD,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC5C;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,cAAc,CAAA;IACpB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,gBAAgB,CAAA;IACtB,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,aAAa,CAAA;IACnB,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3D,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3D,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,UAAU,GAAG,qBAAqB,GAAG,uBAAuB,GAAG,qBAAqB,CAAA;AAEhG,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,CAAC,CAAA;IACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChC,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAkBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,YAAY,CAiGtF"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { collectClasses, collectRelationships } from '../models/arch-class.js';
|
|
2
|
+
const INHERITANCE_ARROWS = new Set(['<|--', '<|..', '--|>', '..|>']);
|
|
3
|
+
const DEPENDENCY_ARROWS = new Set(['-->', '..>', '*--', 'o--', '--']);
|
|
4
|
+
function resolveFolder(className, stereotypes, options) {
|
|
5
|
+
const classMap = options.classToFolder ?? {};
|
|
6
|
+
if (classMap[className])
|
|
7
|
+
return classMap[className];
|
|
8
|
+
if (options.stereotypeToFolder) {
|
|
9
|
+
for (const s of stereotypes) {
|
|
10
|
+
const folder = options.stereotypeToFolder[s];
|
|
11
|
+
if (folder)
|
|
12
|
+
return folder;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
export function fromDiagram(project, options) {
|
|
18
|
+
const classes = collectClasses(project);
|
|
19
|
+
const classByName = new Map(classes.map((c) => [c.name, c]));
|
|
20
|
+
const relationships = collectRelationships(project);
|
|
21
|
+
const layers = { ...(options.classToFolder ?? {}) };
|
|
22
|
+
if (options.stereotypeToFolder) {
|
|
23
|
+
for (const [stereotype, folder] of Object.entries(options.stereotypeToFolder)) {
|
|
24
|
+
layers[stereotype] = folder;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const rules = [];
|
|
28
|
+
const allowedPairs = new Set();
|
|
29
|
+
for (const r of relationships) {
|
|
30
|
+
const lhs = classByName.get(r.source);
|
|
31
|
+
const rhs = classByName.get(r.target);
|
|
32
|
+
if (!lhs || !rhs)
|
|
33
|
+
continue;
|
|
34
|
+
const lhsFolder = resolveFolder(lhs.name, lhs.stereotypes, options);
|
|
35
|
+
const rhsFolder = resolveFolder(rhs.name, rhs.stereotypes, options);
|
|
36
|
+
if (!lhsFolder || !rhsFolder)
|
|
37
|
+
continue;
|
|
38
|
+
if (INHERITANCE_ARROWS.has(r.arrow)) {
|
|
39
|
+
const subClass = r.arrow === '<|--' || r.arrow === '<|..' ? rhs : lhs;
|
|
40
|
+
const supClass = r.arrow === '<|--' || r.arrow === '<|..' ? lhs : rhs;
|
|
41
|
+
const subFolder = resolveFolder(subClass.name, subClass.stereotypes, options);
|
|
42
|
+
const supFolder = resolveFolder(supClass.name, supClass.stereotypes, options);
|
|
43
|
+
if (!subFolder || !supFolder)
|
|
44
|
+
continue;
|
|
45
|
+
rules.push({
|
|
46
|
+
id: `diagram/inherit/${subClass.name}-extends-${supClass.name}`,
|
|
47
|
+
kind: 'inheritance',
|
|
48
|
+
sub: {
|
|
49
|
+
class: subClass.name,
|
|
50
|
+
folder: subFolder,
|
|
51
|
+
stereotype: subClass.stereotypes[0],
|
|
52
|
+
},
|
|
53
|
+
sup: {
|
|
54
|
+
class: supClass.name,
|
|
55
|
+
folder: supFolder,
|
|
56
|
+
stereotype: supClass.stereotypes[0],
|
|
57
|
+
},
|
|
58
|
+
because: `Diagram declares ${subClass.name} extends ${supClass.name}`,
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (DEPENDENCY_ARROWS.has(r.arrow)) {
|
|
63
|
+
rules.push({
|
|
64
|
+
id: `diagram/edge/${lhs.name}-${r.arrow}-${rhs.name}`,
|
|
65
|
+
kind: 'allowed-edge',
|
|
66
|
+
source: {
|
|
67
|
+
class: lhs.name,
|
|
68
|
+
folder: lhsFolder,
|
|
69
|
+
stereotype: lhs.stereotypes[0],
|
|
70
|
+
},
|
|
71
|
+
target: {
|
|
72
|
+
class: rhs.name,
|
|
73
|
+
folder: rhsFolder,
|
|
74
|
+
stereotype: rhs.stereotypes[0],
|
|
75
|
+
},
|
|
76
|
+
arrow: r.arrow,
|
|
77
|
+
because: `Diagram declares ${lhs.name} ${r.arrow} ${rhs.name}`,
|
|
78
|
+
});
|
|
79
|
+
const lhsKey = lhs.stereotypes[0] ?? lhs.name;
|
|
80
|
+
const rhsKey = rhs.stereotypes[0] ?? rhs.name;
|
|
81
|
+
allowedPairs.add(`${lhsKey}|${rhsKey}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Closure rule: any folder pair NOT in allowed set is forbidden
|
|
85
|
+
const layerEntries = Object.entries(layers);
|
|
86
|
+
for (const [a, aFolder] of layerEntries) {
|
|
87
|
+
for (const [b, bFolder] of layerEntries) {
|
|
88
|
+
if (a === b)
|
|
89
|
+
continue;
|
|
90
|
+
if (allowedPairs.has(`${a}|${b}`))
|
|
91
|
+
continue;
|
|
92
|
+
rules.push({
|
|
93
|
+
id: `diagram/forbid/${a}-${b}`,
|
|
94
|
+
kind: 'forbidden-edge',
|
|
95
|
+
source: { folder: aFolder, stereotype: a },
|
|
96
|
+
target: { folder: bFolder, stereotype: b },
|
|
97
|
+
because: `Diagram does not declare any edge from ${a} to ${b}`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const allowed = Array.from(allowedPairs).map((p) => {
|
|
102
|
+
const idx = p.indexOf('|');
|
|
103
|
+
return [p.slice(0, idx), p.slice(idx + 1)];
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
version: 1,
|
|
107
|
+
layers,
|
|
108
|
+
allowed,
|
|
109
|
+
rules,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=from-diagram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-diagram.js","sourceRoot":"","sources":["../../src/bridge/from-diagram.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RuleBuilder } from '@nielspeter/eess';
|
|
2
|
+
import type { ArchProject } from '../core/project.js';
|
|
3
|
+
import { type ArchClass } from '../models/arch-class.js';
|
|
4
|
+
export declare class ClassRuleBuilder extends RuleBuilder<ArchClass, ArchProject> {
|
|
5
|
+
protected getElements(): ArchClass[];
|
|
6
|
+
/**
|
|
7
|
+
* After `.that()`: filter classes carrying the `<<name>>` stereotype.
|
|
8
|
+
* After `.should()`: assert matched classes carry the `<<name>>` stereotype.
|
|
9
|
+
*/
|
|
10
|
+
haveStereotype(name: string): this;
|
|
11
|
+
/** Filter to classes whose name matches the pattern. */
|
|
12
|
+
haveNameMatching(pattern: RegExp): this;
|
|
13
|
+
/** Filter to classes whose name starts with the given prefix. */
|
|
14
|
+
haveNameStartingWith(prefix: string): this;
|
|
15
|
+
/** Filter to classes whose name ends with the given suffix. */
|
|
16
|
+
haveNameEndingWith(suffix: string): this;
|
|
17
|
+
/** Filter to classes declaring a member (field or method) with the given name. */
|
|
18
|
+
haveMemberNamed(name: string): this;
|
|
19
|
+
/** Filter to classes declaring a method with the given name. */
|
|
20
|
+
haveMethodNamed(name: string): this;
|
|
21
|
+
/** Filter to classes marked `<<abstract>>`. */
|
|
22
|
+
areAbstract(): this;
|
|
23
|
+
/** Filter to classes declaring at least one method. */
|
|
24
|
+
haveAtLeastOneMethod(): this;
|
|
25
|
+
/** Filter to classes with no members (empty body). */
|
|
26
|
+
haveNoMembers(): this;
|
|
27
|
+
/** Filter to classes that extend the named superclass. */
|
|
28
|
+
extendName(superName: string): this;
|
|
29
|
+
/** Assert matched classes do not extend a class carrying the `<<name>>` stereotype. */
|
|
30
|
+
notExtendStereotype(name: string): this;
|
|
31
|
+
/** Assert matched classes extend the named superclass. */
|
|
32
|
+
extend(superName: string): this;
|
|
33
|
+
/** Assert no class matched the preceding filters (the selection must be empty). */
|
|
34
|
+
notExist(): this;
|
|
35
|
+
/** Assert matched classes do not carry the `<<name>>` stereotype. */
|
|
36
|
+
notHaveStereotype(name: string): this;
|
|
37
|
+
/** Assert matched classes depend on the named target class. */
|
|
38
|
+
dependOn(targetName: string): this;
|
|
39
|
+
/** Assert matched classes do not depend on the named target class. */
|
|
40
|
+
notDependOn(targetName: string): this;
|
|
41
|
+
/** Assert matched classes do not depend on any class carrying the `<<stereotype>>`. */
|
|
42
|
+
notDependOnStereotype(stereotype: string): this;
|
|
43
|
+
}
|
|
44
|
+
export declare function classes(project: ArchProject): ClassRuleBuilder;
|
|
45
|
+
//# sourceMappingURL=class-rule-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class-rule-builder.d.ts","sourceRoot":"","sources":["../../src/builders/class-rule-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAwBxE,qBAAa,gBAAiB,SAAQ,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC;IACvE,SAAS,CAAC,WAAW,IAAI,SAAS,EAAE;IAMpC;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOlC,wDAAwD;IACxD,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIvC,iEAAiE;IACjE,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI1C,+DAA+D;IAC/D,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIxC,kFAAkF;IAClF,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAInC,gEAAgE;IAChE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAInC,+CAA+C;IAC/C,WAAW,IAAI,IAAI;IAInB,uDAAuD;IACvD,oBAAoB,IAAI,IAAI;IAI5B,sDAAsD;IACtD,aAAa,IAAI,IAAI;IAIrB,0DAA0D;IAC1D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMnC,uFAAuF;IACvF,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIvC,0DAA0D;IAC1D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI/B,mFAAmF;IACnF,QAAQ,IAAI,IAAI;IAIhB,qEAAqE;IACrE,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIrC,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIlC,sEAAsE;IACtE,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIrC,uFAAuF;IACvF,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;CAGhD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,gBAAgB,CAE9D"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { RuleBuilder } from '@nielspeter/eess';
|
|
2
|
+
import { collectClasses } from '../models/arch-class.js';
|
|
3
|
+
import { haveStereotype as predHaveStereotype, haveNameMatching as predHaveNameMatching, haveNameStartingWith as predHaveNameStartingWith, haveNameEndingWith as predHaveNameEndingWith, haveMemberNamed as predHaveMemberNamed, haveMethodNamed as predHaveMethodNamed, areAbstract as predAreAbstract, haveAtLeastOneMethod as predHaveAtLeastOneMethod, haveNoMembers as predHaveNoMembers, extendName as predExtendName, } from '../predicates/class.js';
|
|
4
|
+
import { notExtendStereotype as condNotExtendStereotype, extendClass as condExtendClass, notExist as condNotExist, haveStereotype as condHaveStereotype, notHaveStereotype as condNotHaveStereotype, dependOn as condDependOn, notDependOn as condNotDependOn, notDependOnStereotype as condNotDependOnStereotype, } from '../conditions/class.js';
|
|
5
|
+
export class ClassRuleBuilder extends RuleBuilder {
|
|
6
|
+
getElements() {
|
|
7
|
+
return collectClasses(this.project);
|
|
8
|
+
}
|
|
9
|
+
// --- Predicate methods (after .that()) ---
|
|
10
|
+
/**
|
|
11
|
+
* After `.that()`: filter classes carrying the `<<name>>` stereotype.
|
|
12
|
+
* After `.should()`: assert matched classes carry the `<<name>>` stereotype.
|
|
13
|
+
*/
|
|
14
|
+
haveStereotype(name) {
|
|
15
|
+
if (this._phase === 'condition') {
|
|
16
|
+
return this.addCondition(condHaveStereotype(name));
|
|
17
|
+
}
|
|
18
|
+
return this.addPredicate(predHaveStereotype(name));
|
|
19
|
+
}
|
|
20
|
+
/** Filter to classes whose name matches the pattern. */
|
|
21
|
+
haveNameMatching(pattern) {
|
|
22
|
+
return this.addPredicate(predHaveNameMatching(pattern));
|
|
23
|
+
}
|
|
24
|
+
/** Filter to classes whose name starts with the given prefix. */
|
|
25
|
+
haveNameStartingWith(prefix) {
|
|
26
|
+
return this.addPredicate(predHaveNameStartingWith(prefix));
|
|
27
|
+
}
|
|
28
|
+
/** Filter to classes whose name ends with the given suffix. */
|
|
29
|
+
haveNameEndingWith(suffix) {
|
|
30
|
+
return this.addPredicate(predHaveNameEndingWith(suffix));
|
|
31
|
+
}
|
|
32
|
+
/** Filter to classes declaring a member (field or method) with the given name. */
|
|
33
|
+
haveMemberNamed(name) {
|
|
34
|
+
return this.addPredicate(predHaveMemberNamed(name));
|
|
35
|
+
}
|
|
36
|
+
/** Filter to classes declaring a method with the given name. */
|
|
37
|
+
haveMethodNamed(name) {
|
|
38
|
+
return this.addPredicate(predHaveMethodNamed(name));
|
|
39
|
+
}
|
|
40
|
+
/** Filter to classes marked `<<abstract>>`. */
|
|
41
|
+
areAbstract() {
|
|
42
|
+
return this.addPredicate(predAreAbstract());
|
|
43
|
+
}
|
|
44
|
+
/** Filter to classes declaring at least one method. */
|
|
45
|
+
haveAtLeastOneMethod() {
|
|
46
|
+
return this.addPredicate(predHaveAtLeastOneMethod());
|
|
47
|
+
}
|
|
48
|
+
/** Filter to classes with no members (empty body). */
|
|
49
|
+
haveNoMembers() {
|
|
50
|
+
return this.addPredicate(predHaveNoMembers());
|
|
51
|
+
}
|
|
52
|
+
/** Filter to classes that extend the named superclass. */
|
|
53
|
+
extendName(superName) {
|
|
54
|
+
return this.addPredicate(predExtendName(superName));
|
|
55
|
+
}
|
|
56
|
+
// --- Condition methods (after .should()) ---
|
|
57
|
+
/** Assert matched classes do not extend a class carrying the `<<name>>` stereotype. */
|
|
58
|
+
notExtendStereotype(name) {
|
|
59
|
+
return this.addCondition(condNotExtendStereotype(name));
|
|
60
|
+
}
|
|
61
|
+
/** Assert matched classes extend the named superclass. */
|
|
62
|
+
extend(superName) {
|
|
63
|
+
return this.addCondition(condExtendClass(superName));
|
|
64
|
+
}
|
|
65
|
+
/** Assert no class matched the preceding filters (the selection must be empty). */
|
|
66
|
+
notExist() {
|
|
67
|
+
return this.addCondition(condNotExist());
|
|
68
|
+
}
|
|
69
|
+
/** Assert matched classes do not carry the `<<name>>` stereotype. */
|
|
70
|
+
notHaveStereotype(name) {
|
|
71
|
+
return this.addCondition(condNotHaveStereotype(name));
|
|
72
|
+
}
|
|
73
|
+
/** Assert matched classes depend on the named target class. */
|
|
74
|
+
dependOn(targetName) {
|
|
75
|
+
return this.addCondition(condDependOn(targetName));
|
|
76
|
+
}
|
|
77
|
+
/** Assert matched classes do not depend on the named target class. */
|
|
78
|
+
notDependOn(targetName) {
|
|
79
|
+
return this.addCondition(condNotDependOn(targetName));
|
|
80
|
+
}
|
|
81
|
+
/** Assert matched classes do not depend on any class carrying the `<<stereotype>>`. */
|
|
82
|
+
notDependOnStereotype(stereotype) {
|
|
83
|
+
return this.addCondition(condNotDependOnStereotype(stereotype));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function classes(project) {
|
|
87
|
+
return new ClassRuleBuilder(project);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=class-rule-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class-rule-builder.js","sourceRoot":"","sources":["../../src/builders/class-rule-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":""}
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAEhC,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OutputFormat } from '@nielspeter/eess';
|
|
2
|
+
export interface CheckArgs {
|
|
3
|
+
ruleFiles: string[];
|
|
4
|
+
format: OutputFormat | 'auto';
|
|
5
|
+
fresh?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function runCheck(args: CheckArgs): Promise<number>;
|
|
8
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGlE,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,MAAM,EAAE,YAAY,GAAG,MAAM,CAAA;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AASD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAqC/D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { detectFormat } from '@nielspeter/eess';
|
|
2
|
+
import { loadRuleFiles } from '../load-rules.js';
|
|
3
|
+
function isArchRuleError(value) {
|
|
4
|
+
if (value === null || typeof value !== 'object')
|
|
5
|
+
return false;
|
|
6
|
+
// Duck-type: ArchRuleError class identity is unreliable across jiti boundaries
|
|
7
|
+
// because the rule file may load its own copy of the kernel. Match by name.
|
|
8
|
+
return 'name' in value && typeof value.name === 'string' && value.name === 'ArchRuleError';
|
|
9
|
+
}
|
|
10
|
+
export async function runCheck(args) {
|
|
11
|
+
const started = Date.now();
|
|
12
|
+
const format = args.format === 'auto' ? detectFormat() : args.format;
|
|
13
|
+
const options = { format };
|
|
14
|
+
const loadOptions = { fresh: args.fresh };
|
|
15
|
+
const builders = await loadRuleFiles(args.ruleFiles, loadOptions);
|
|
16
|
+
let failures = 0;
|
|
17
|
+
for (const builder of builders) {
|
|
18
|
+
try {
|
|
19
|
+
builder.check(options);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (isArchRuleError(error)) {
|
|
23
|
+
failures++;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Report the denominator so a fast green is provably non-vacuous, not silence.
|
|
31
|
+
// Terminal only — JSON/GitHub-annotation output on stdout stays machine-clean.
|
|
32
|
+
if (format === 'terminal') {
|
|
33
|
+
const ms = Date.now() - started;
|
|
34
|
+
const time = ms < 1000 ? `${ms}ms` : `${(ms / 1000).toFixed(2)}s`;
|
|
35
|
+
const rules = builders.length;
|
|
36
|
+
const files = args.ruleFiles.length;
|
|
37
|
+
const scope = `${rules} rule${rules === 1 ? '' : 's'} across ${files} file${files === 1 ? '' : 's'}`;
|
|
38
|
+
process.stderr.write(failures === 0
|
|
39
|
+
? `\n✓ eess-mermaid — ${scope} · 0 failing (${time})\n`
|
|
40
|
+
: `\n✗ eess-mermaid — ${failures} of ${scope} failing (${time})\n`);
|
|
41
|
+
}
|
|
42
|
+
return failures;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,OAAO,EAAE,aAAa,EAA0C,MAAM,kBAAkB,CAAA;AAQxF,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC7D,+EAA+E;IAC/E,4EAA4E;IAC5E,OAAO,MAAM,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,CAAA;AAC5F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAe;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAiB,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAA;IAClF,MAAM,OAAO,GAAiB,EAAE,MAAM,EAAE,CAAA;IAExC,MAAM,WAAW,GAAgB,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;IACtD,MAAM,QAAQ,GAAsB,MAAM,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IAEpF,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACxB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3B,QAAQ,EAAE,CAAA;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAA;YACb,CAAC;QACH,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,+EAA+E;IAC/E,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;QAC/B,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAA;QACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAA;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAA;QACnC,MAAM,KAAK,GAAG,GAAG,KAAK,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;QACpG,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,QAAQ,KAAK,CAAC;YACZ,CAAC,CAAC,sBAAsB,KAAK,iBAAiB,IAAI,KAAK;YACvD,CAAC,CAAC,sBAAsB,QAAQ,OAAO,KAAK,aAAa,IAAI,KAAK,CACrE,CAAA;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAcD,wBAAsB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { loadRuleFiles } from '../load-rules.js';
|
|
2
|
+
function isRuleDescription(value) {
|
|
3
|
+
return value !== null && typeof value === 'object';
|
|
4
|
+
}
|
|
5
|
+
export async function runExplain(args) {
|
|
6
|
+
const builders = await loadRuleFiles(args.ruleFiles);
|
|
7
|
+
const rules = [];
|
|
8
|
+
for (const builder of builders) {
|
|
9
|
+
if (typeof builder.describeRule !== 'function')
|
|
10
|
+
continue;
|
|
11
|
+
const desc = builder.describeRule();
|
|
12
|
+
if (isRuleDescription(desc))
|
|
13
|
+
rules.push(desc);
|
|
14
|
+
}
|
|
15
|
+
if (args.markdown === true) {
|
|
16
|
+
process.stdout.write(formatMarkdown(rules));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
process.stdout.write(JSON.stringify({ rules }, null, 2) + '\n');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function formatMarkdown(rules) {
|
|
23
|
+
const header = '| ID | Rule | Because | Suggestion |\n|---|---|---|---|\n';
|
|
24
|
+
const rows = rules
|
|
25
|
+
.map((r) => `| ${r.id ?? ''} | ${r.rule ?? ''} | ${r.because ?? ''} | ${r.suggestion ?? ''} |`)
|
|
26
|
+
.join('\n');
|
|
27
|
+
return header + rows + '\n';
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=explain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAehD,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAA;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAiB;IAChD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACpD,MAAM,KAAK,GAA0B,EAAE,CAAA;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,OAAO,CAAC,YAAY,KAAK,UAAU;YAAE,SAAQ;QACxD,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,EAAE,CAAA;QACnC,IAAI,iBAAiB,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACjE,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAA4B;IAClD,MAAM,MAAM,GAAG,2DAA2D,CAAA;IAC1E,MAAM,IAAI,GAAG,KAAK;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,IAAI,EAAE,IAAI,CAAC;SAC9F,IAAI,CAAC,IAAI,CAAC,CAAA;IACb,OAAO,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;AAC7B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OutputFormat } from '@nielspeter/eess';
|
|
2
|
+
export interface CliConfig {
|
|
3
|
+
rules?: string[];
|
|
4
|
+
format?: OutputFormat | 'auto';
|
|
5
|
+
watchDirs?: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function defineConfig(config: CliConfig): CliConfig;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAEpD,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAEzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAmHA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CvD"}
|