@aoelite/refpact-ts 0.0.0-stage → 0.2.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 +38 -2
- package/dist/baseline.d.ts +26 -0
- package/dist/baseline.js +65 -0
- package/dist/core/index.d.ts +88 -0
- package/dist/core/index.js +105 -0
- package/dist/core/model.d.ts +340 -0
- package/dist/core/model.js +1 -0
- package/dist/core/results.d.ts +268 -0
- package/dist/core/results.js +1 -0
- package/dist/core/wasm.d.ts +7 -0
- package/dist/core/wasm.js +67 -0
- package/dist/custom.d.ts +166 -0
- package/dist/custom.js +239 -0
- package/dist/filters.d.ts +73 -0
- package/dist/filters.js +39 -0
- package/dist/frontend/checks.d.ts +15 -0
- package/dist/frontend/checks.js +12 -0
- package/dist/frontend/classic.d.ts +3 -0
- package/dist/frontend/classic.js +105 -0
- package/dist/frontend/compiler.d.ts +93 -0
- package/dist/frontend/compiler.js +116 -0
- package/dist/frontend/components.d.ts +29 -0
- package/dist/frontend/components.js +111 -0
- package/dist/frontend/declarations.d.ts +45 -0
- package/dist/frontend/declarations.js +158 -0
- package/dist/frontend/dependencies.d.ts +53 -0
- package/dist/frontend/dependencies.js +337 -0
- package/dist/frontend/imports.d.ts +149 -0
- package/dist/frontend/imports.js +765 -0
- package/dist/frontend/native.d.ts +3 -0
- package/dist/frontend/native.js +165 -0
- package/dist/frontend/paths.d.ts +10 -0
- package/dist/frontend/paths.js +18 -0
- package/dist/frontend/project.d.ts +118 -0
- package/dist/frontend/project.js +775 -0
- package/dist/group.d.ts +74 -0
- package/dist/group.js +106 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +27 -0
- package/dist/items.d.ts +133 -0
- package/dist/items.js +179 -0
- package/dist/layers.d.ts +112 -0
- package/dist/layers.js +215 -0
- package/dist/onion.d.ts +78 -0
- package/dist/onion.js +96 -0
- package/dist/patterns.d.ts +14 -0
- package/dist/patterns.js +15 -0
- package/dist/rules.d.ts +408 -0
- package/dist/rules.js +665 -0
- package/package.json +52 -4
- package/wasm/refpact_core.wasm +0 -0
package/dist/layers.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/** Layers: rules about which layers of an architecture may import which. */
|
|
2
|
+
import { addFilters } from "./filters.js";
|
|
3
|
+
import { RuleSet } from "./group.js";
|
|
4
|
+
import { filePattern } from "./patterns.js";
|
|
5
|
+
import { all, AnyOf, anyOf, ArchitectureError, Files, rule } from "./rules.js";
|
|
6
|
+
export class Layers extends RuleSet {
|
|
7
|
+
settings;
|
|
8
|
+
/** @internal */
|
|
9
|
+
constructor(settings) {
|
|
10
|
+
super();
|
|
11
|
+
this.settings = settings;
|
|
12
|
+
}
|
|
13
|
+
/** The name of the layers. */
|
|
14
|
+
get name() {
|
|
15
|
+
return this.settings.name;
|
|
16
|
+
}
|
|
17
|
+
/** Adds a layer below the layers that are there. */
|
|
18
|
+
layer(name, ...files) {
|
|
19
|
+
return this.with({ list: [...this.settings.list, { name, files }] });
|
|
20
|
+
}
|
|
21
|
+
/** @internal The layers with one more filter. */
|
|
22
|
+
filtered(filter) {
|
|
23
|
+
return this.with({ filters: [...this.settings.filters, filter] });
|
|
24
|
+
}
|
|
25
|
+
/** Makes the layers strict: a layer may import only the layer right below it, not the layers further down. */
|
|
26
|
+
strict() {
|
|
27
|
+
return this.with({ strict: true });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The layer may import only these layers. Each of them must be below it, and right below
|
|
31
|
+
* it when the layers are {@link Layers.strict | strict}. No layers forbids the layer to
|
|
32
|
+
* import any other layer.
|
|
33
|
+
*/
|
|
34
|
+
mayOnlyImport(layer, ...layers) {
|
|
35
|
+
return this.with({ mayOnlyImport: [...this.settings.mayOnlyImport, [layer, layers]] });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Only these layers may import the layer. Each of them must be above it, and right above
|
|
39
|
+
* it when the layers are {@link Layers.strict | strict}. No layers forbids every other layer
|
|
40
|
+
* to import it.
|
|
41
|
+
*
|
|
42
|
+
* This is about the layers only. To keep every other file away as well, add a rule with
|
|
43
|
+
* {@link ScopedRule.mustOnlyBeImportedBy}.
|
|
44
|
+
*/
|
|
45
|
+
mayOnlyBeImportedBy(layer, ...layers) {
|
|
46
|
+
return this.with({ mayOnlyBeImportedBy: [...this.settings.mayOnlyBeImportedBy, [layer, layers]] });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Each of these files must be in a layer. A new file then cannot stay out of the
|
|
50
|
+
* architecture unseen. Leave out the files that belong to no layer, such as the entry
|
|
51
|
+
* point: `allExcept("src/main.ts")`.
|
|
52
|
+
*/
|
|
53
|
+
everyFileInALayer(files) {
|
|
54
|
+
return this.with({ covered: files });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The rules of the layers: one `mustNotImport` rule for each layer that must not import
|
|
58
|
+
* some other layers, and the rule of {@link Layers.everyFileInALayer} when it is given.
|
|
59
|
+
*
|
|
60
|
+
* The rule of a layer has the name of the layers and the name of the layer. It is
|
|
61
|
+
* `<layers>: <layer> does not import the layers above it` when only the order of the
|
|
62
|
+
* layers applies to the layer, and `<layers>: <layer> imports only the layers it may
|
|
63
|
+
* import` when more applies.
|
|
64
|
+
*
|
|
65
|
+
* Throws an {@link ArchitectureError} of type `malformed` when the layers cannot fail as
|
|
66
|
+
* written or name a layer that does not exist.
|
|
67
|
+
*/
|
|
68
|
+
rules() {
|
|
69
|
+
const settings = this.settings;
|
|
70
|
+
const allowed = this.allowed();
|
|
71
|
+
if (!Array.isArray(allowed)) {
|
|
72
|
+
throw new ArchitectureError(allowed);
|
|
73
|
+
}
|
|
74
|
+
const made = [];
|
|
75
|
+
settings.list.forEach((layer, from) => {
|
|
76
|
+
const forbidden = forbiddenFor(allowed, from);
|
|
77
|
+
if (forbidden.length === 0) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const onlyAbove = forbidden.length === from && forbidden.every((to, index) => to === index);
|
|
81
|
+
const name = onlyAbove
|
|
82
|
+
? `${settings.name}: ${layer.name} does not import the layers above it`
|
|
83
|
+
: `${settings.name}: ${layer.name} imports only the layers it may import`;
|
|
84
|
+
const targets = forbidden.flatMap((to) => settings.list[to]?.files ?? []);
|
|
85
|
+
const one = rule(name)
|
|
86
|
+
.files(anyOf(...layer.files))
|
|
87
|
+
.mustNotImport(anyOf(...targets));
|
|
88
|
+
made.push(this.withFilters(one, true));
|
|
89
|
+
});
|
|
90
|
+
if (settings.covered !== undefined) {
|
|
91
|
+
const places = settings.list.flatMap((layer) => layer.files);
|
|
92
|
+
const covered = rule(`${settings.name}: every file is in a layer`).files(settings.covered).mustBeIn(places);
|
|
93
|
+
made.push(this.withFilters(covered, false));
|
|
94
|
+
}
|
|
95
|
+
return made;
|
|
96
|
+
}
|
|
97
|
+
/** The rule with the filters of the layers. A rule that looks at no import gets only the filters that are not about imports. */
|
|
98
|
+
withFilters(made, seesImports) {
|
|
99
|
+
const filters = this.settings.filters.filter((filter) => seesImports || !filter.aboutImports);
|
|
100
|
+
return filters.reduce((one, filter) => one.filtered(filter), made);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A diagram of the layers, in Mermaid (the default) or DOT, from the top to the bottom. Each
|
|
104
|
+
* layer is a node, and an edge is an import between two layers. An import that the layers
|
|
105
|
+
* forbid is red. A file is in the first layer that matches it, and a file in no layer is
|
|
106
|
+
* not drawn. The files of {@link Layers.everyFileInALayer} are not checked.
|
|
107
|
+
*
|
|
108
|
+
* Throws an {@link ArchitectureError}: `malformed` as {@link Layers.rules} does, or
|
|
109
|
+
* `invalid` when a pattern of a layer matches no file.
|
|
110
|
+
*
|
|
111
|
+
* ```ts
|
|
112
|
+
* const text = layers("the layers").layer("ui", "src/ui/**").layer("db", "src/db/**").diagram(app);
|
|
113
|
+
* writeFileSync("docs/layers.md", `\`\`\`mermaid\n${text}\`\`\`\n`);
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
diagram(project, format = "mermaid") {
|
|
117
|
+
const settings = this.settings;
|
|
118
|
+
const allowed = this.allowed();
|
|
119
|
+
if (!Array.isArray(allowed)) {
|
|
120
|
+
throw new ArchitectureError(allowed);
|
|
121
|
+
}
|
|
122
|
+
const list = settings.list.map((layer, from) => ({
|
|
123
|
+
name: layer.name,
|
|
124
|
+
units: layer.files.map(filePattern),
|
|
125
|
+
mustNotUse: forbiddenFor(allowed, from),
|
|
126
|
+
}));
|
|
127
|
+
const drawn = rule(settings.name).files(all()).mustBeImported();
|
|
128
|
+
return this.withFilters(drawn, true).draw(project, { layers: list }, format);
|
|
129
|
+
}
|
|
130
|
+
/** For each layer, by position from the top, the layers it may import; or every problem of the layers. */
|
|
131
|
+
allowed() {
|
|
132
|
+
const { name, list, strict } = this.settings;
|
|
133
|
+
const malformed = (problems) => ({
|
|
134
|
+
type: "malformed",
|
|
135
|
+
rule: name,
|
|
136
|
+
message: `rule \`${name}\` cannot be checked:\n ${problems.join("\n ")}`,
|
|
137
|
+
});
|
|
138
|
+
const count = list.length;
|
|
139
|
+
if (count < 2) {
|
|
140
|
+
return malformed(["fewer than two layers are given, so no layer can import a layer above it"]);
|
|
141
|
+
}
|
|
142
|
+
const problems = [];
|
|
143
|
+
list.forEach((layer, position) => {
|
|
144
|
+
if (list.slice(0, position).some((other) => other.name === layer.name)) {
|
|
145
|
+
problems.push(`two layers have the name \`${layer.name}\``);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
// What the order allows: the layers below, or only the next one when strict.
|
|
149
|
+
const ordered = (from, to) => to > from && (!strict || to === from + 1);
|
|
150
|
+
const allowed = list.map((_, from) => list.map((__, to) => ordered(from, to)));
|
|
151
|
+
const position = (layer) => {
|
|
152
|
+
const found = list.findIndex((entry) => entry.name === layer);
|
|
153
|
+
if (found === -1) {
|
|
154
|
+
problems.push(`\`${layer}\` is not a layer`);
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
return found;
|
|
158
|
+
};
|
|
159
|
+
const restrict = (lists, twice, forbidden, edge) => {
|
|
160
|
+
const seen = new Set();
|
|
161
|
+
for (const [layer, others] of lists) {
|
|
162
|
+
const at = position(layer);
|
|
163
|
+
if (at === undefined) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (seen.has(at)) {
|
|
167
|
+
problems.push(twice(layer));
|
|
168
|
+
}
|
|
169
|
+
seen.add(at);
|
|
170
|
+
const keep = list.map(() => false);
|
|
171
|
+
for (const other of others) {
|
|
172
|
+
const otherAt = position(other);
|
|
173
|
+
if (otherAt === undefined) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const [from, to] = edge(at, otherAt);
|
|
177
|
+
if (ordered(from, to)) {
|
|
178
|
+
keep[otherAt] = true;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
problems.push(forbidden(layer, other));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
keep.forEach((kept, otherAt) => {
|
|
185
|
+
const [from, to] = edge(at, otherAt);
|
|
186
|
+
const row = allowed[from];
|
|
187
|
+
row[to] = row[to] === true && kept;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
restrict(this.settings.mayOnlyImport, (layer) => `\`${layer}\` has two lists of the layers it may import`, (layer, other) => `\`${layer}\` may only import \`${other}\`, which the order of the layers forbids`, (layer, other) => [layer, other]);
|
|
192
|
+
restrict(this.settings.mayOnlyBeImportedBy, (layer) => `\`${layer}\` has two lists of the layers that may import it`, (layer, other) => `\`${layer}\` may only be imported by \`${other}\`, which the order of the layers forbids`, (layer, other) => [other, layer]);
|
|
193
|
+
return problems.length === 0 ? allowed : malformed(problems);
|
|
194
|
+
}
|
|
195
|
+
with(change) {
|
|
196
|
+
return new Layers({ ...this.settings, ...change });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** The layers that a layer must not import, by position from the top, from what each layer may import. */
|
|
200
|
+
function forbiddenFor(allowed, from) {
|
|
201
|
+
return allowed.map((_, to) => to).filter((to) => to !== from && allowed[from]?.[to] !== true);
|
|
202
|
+
}
|
|
203
|
+
/** Starts a set of layers. Add the layers from the top to the bottom. */
|
|
204
|
+
export function layers(name) {
|
|
205
|
+
return new Layers({
|
|
206
|
+
name,
|
|
207
|
+
list: [],
|
|
208
|
+
filters: [],
|
|
209
|
+
strict: false,
|
|
210
|
+
mayOnlyImport: [],
|
|
211
|
+
mayOnlyBeImportedBy: [],
|
|
212
|
+
covered: undefined,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
addFilters(Layers);
|
package/dist/onion.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Filter, Filters } from "./filters.ts";
|
|
2
|
+
import { RuleSet } from "./group.ts";
|
|
3
|
+
import { Layers } from "./layers.ts";
|
|
4
|
+
import type { DiagramFormat } from "./core/index.ts";
|
|
5
|
+
import type { Project } from "./frontend/project.ts";
|
|
6
|
+
import type { AnyOf, Files, ImportRule } from "./rules.ts";
|
|
7
|
+
interface Parts {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly domainModels: readonly string[] | undefined;
|
|
10
|
+
readonly domainServices: readonly string[] | undefined;
|
|
11
|
+
readonly applicationServices: readonly string[] | undefined;
|
|
12
|
+
readonly adapters: readonly {
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly files: readonly string[];
|
|
15
|
+
}[];
|
|
16
|
+
/** The filters of every rule of the architecture. */
|
|
17
|
+
readonly filters: readonly Filter[];
|
|
18
|
+
readonly covered: AnyOf<string> | Files | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The parts of an onion architecture. From the inside out:
|
|
22
|
+
*
|
|
23
|
+
* - the **domain models**, which import no other part;
|
|
24
|
+
* - the **domain services**, which may import the domain models;
|
|
25
|
+
* - the **application services**, which may import the domain;
|
|
26
|
+
* - the **adapters**, such as a web interface or a database, which may import the
|
|
27
|
+
* application services and the domain, but not each other.
|
|
28
|
+
*
|
|
29
|
+
* Give the parts that the code has; at least two of them. The rules are those of
|
|
30
|
+
* {@link layers}, one layer for each part, and each adapter a layer of its own.
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* onionArchitecture("the shop")
|
|
34
|
+
* .domainModels("src/domain/model/**")
|
|
35
|
+
* .domainServices("src/domain/service/**")
|
|
36
|
+
* .applicationServices("src/application/**")
|
|
37
|
+
* .adapter("web", "src/adapter/web/**")
|
|
38
|
+
* .adapter("database", "src/adapter/db/**")
|
|
39
|
+
* .check(app);
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* The filters of a rule ({@link Filters}), such as `ignoringTypeImports()`, apply to every
|
|
43
|
+
* part.
|
|
44
|
+
*/
|
|
45
|
+
export interface Onion extends Filters<Onion> {
|
|
46
|
+
}
|
|
47
|
+
export declare class Onion extends RuleSet {
|
|
48
|
+
private readonly parts;
|
|
49
|
+
/** @internal */
|
|
50
|
+
constructor(parts: Parts);
|
|
51
|
+
/** The name of the architecture. */
|
|
52
|
+
get name(): string;
|
|
53
|
+
/** The files of the domain models: the centre, which imports no other part. */
|
|
54
|
+
domainModels(...files: string[]): Onion;
|
|
55
|
+
/** The files of the domain services, which may import the domain models. */
|
|
56
|
+
domainServices(...files: string[]): Onion;
|
|
57
|
+
/** The files of the application services, which may import the domain. */
|
|
58
|
+
applicationServices(...files: string[]): Onion;
|
|
59
|
+
/**
|
|
60
|
+
* Adds an adapter. It may import the application services and the domain, and no other
|
|
61
|
+
* adapter may import it. Its layer is named `adapter <name>`.
|
|
62
|
+
*/
|
|
63
|
+
adapter(name: string, ...files: string[]): Onion;
|
|
64
|
+
/** @internal The architecture with one more filter. */
|
|
65
|
+
filtered(filter: Filter): Onion;
|
|
66
|
+
/** Each of these files must be in a part. See {@link Layers.everyFileInALayer}. */
|
|
67
|
+
everyFileInALayer(files: AnyOf<string> | Files): Onion;
|
|
68
|
+
/** The parts as layers, from the outside in. */
|
|
69
|
+
asLayers(): Layers;
|
|
70
|
+
/** A diagram of the parts as layers. See {@link Layers.diagram}. */
|
|
71
|
+
diagram(project: Project, format?: DiagramFormat): string;
|
|
72
|
+
/** The rules of the architecture. See {@link Layers.rules}. */
|
|
73
|
+
rules(): ImportRule[];
|
|
74
|
+
private with;
|
|
75
|
+
}
|
|
76
|
+
/** Starts an onion architecture. See {@link Onion}. */
|
|
77
|
+
export declare function onionArchitecture(name: string): Onion;
|
|
78
|
+
export {};
|
package/dist/onion.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The onion architecture, also called the hexagonal architecture or ports and adapters:
|
|
3
|
+
* layers with the domain at the centre and the adapters outside.
|
|
4
|
+
*/
|
|
5
|
+
import { addFilters } from "./filters.js";
|
|
6
|
+
import { RuleSet } from "./group.js";
|
|
7
|
+
import { layers, Layers } from "./layers.js";
|
|
8
|
+
export class Onion extends RuleSet {
|
|
9
|
+
parts;
|
|
10
|
+
/** @internal */
|
|
11
|
+
constructor(parts) {
|
|
12
|
+
super();
|
|
13
|
+
this.parts = parts;
|
|
14
|
+
}
|
|
15
|
+
/** The name of the architecture. */
|
|
16
|
+
get name() {
|
|
17
|
+
return this.parts.name;
|
|
18
|
+
}
|
|
19
|
+
/** The files of the domain models: the centre, which imports no other part. */
|
|
20
|
+
domainModels(...files) {
|
|
21
|
+
return this.with({ domainModels: files });
|
|
22
|
+
}
|
|
23
|
+
/** The files of the domain services, which may import the domain models. */
|
|
24
|
+
domainServices(...files) {
|
|
25
|
+
return this.with({ domainServices: files });
|
|
26
|
+
}
|
|
27
|
+
/** The files of the application services, which may import the domain. */
|
|
28
|
+
applicationServices(...files) {
|
|
29
|
+
return this.with({ applicationServices: files });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Adds an adapter. It may import the application services and the domain, and no other
|
|
33
|
+
* adapter may import it. Its layer is named `adapter <name>`.
|
|
34
|
+
*/
|
|
35
|
+
adapter(name, ...files) {
|
|
36
|
+
return this.with({ adapters: [...this.parts.adapters, { name, files }] });
|
|
37
|
+
}
|
|
38
|
+
/** @internal The architecture with one more filter. */
|
|
39
|
+
filtered(filter) {
|
|
40
|
+
return this.with({ filters: [...this.parts.filters, filter] });
|
|
41
|
+
}
|
|
42
|
+
/** Each of these files must be in a part. See {@link Layers.everyFileInALayer}. */
|
|
43
|
+
everyFileInALayer(files) {
|
|
44
|
+
return this.with({ covered: files });
|
|
45
|
+
}
|
|
46
|
+
/** The parts as layers, from the outside in. */
|
|
47
|
+
asLayers() {
|
|
48
|
+
const parts = this.parts;
|
|
49
|
+
const adapter = (name) => `adapter ${name}`;
|
|
50
|
+
let made = layers(parts.name);
|
|
51
|
+
for (const { name, files } of parts.adapters) {
|
|
52
|
+
made = made.layer(adapter(name), ...files);
|
|
53
|
+
}
|
|
54
|
+
const inner = [
|
|
55
|
+
["application services", parts.applicationServices],
|
|
56
|
+
["domain services", parts.domainServices],
|
|
57
|
+
["domain models", parts.domainModels],
|
|
58
|
+
].flatMap(([name, files]) => (files !== undefined ? [{ name, files }] : []));
|
|
59
|
+
for (const { name, files } of inner) {
|
|
60
|
+
made = made.layer(name, ...files);
|
|
61
|
+
}
|
|
62
|
+
// An adapter is above the adapters that follow it, but may not import them.
|
|
63
|
+
for (const { name } of parts.adapters) {
|
|
64
|
+
made = made.mayOnlyImport(adapter(name), ...inner.map((part) => part.name));
|
|
65
|
+
}
|
|
66
|
+
made = parts.filters.reduce((layers, filter) => layers.filtered(filter), made);
|
|
67
|
+
if (parts.covered !== undefined) {
|
|
68
|
+
made = made.everyFileInALayer(parts.covered);
|
|
69
|
+
}
|
|
70
|
+
return made;
|
|
71
|
+
}
|
|
72
|
+
/** A diagram of the parts as layers. See {@link Layers.diagram}. */
|
|
73
|
+
diagram(project, format = "mermaid") {
|
|
74
|
+
return this.asLayers().diagram(project, format);
|
|
75
|
+
}
|
|
76
|
+
/** The rules of the architecture. See {@link Layers.rules}. */
|
|
77
|
+
rules() {
|
|
78
|
+
return this.asLayers().rules();
|
|
79
|
+
}
|
|
80
|
+
with(change) {
|
|
81
|
+
return new Onion({ ...this.parts, ...change });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Starts an onion architecture. See {@link Onion}. */
|
|
85
|
+
export function onionArchitecture(name) {
|
|
86
|
+
return new Onion({
|
|
87
|
+
name,
|
|
88
|
+
domainModels: undefined,
|
|
89
|
+
domainServices: undefined,
|
|
90
|
+
applicationServices: undefined,
|
|
91
|
+
adapters: [],
|
|
92
|
+
filters: [],
|
|
93
|
+
covered: undefined,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
addFilters(Onion);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Patterns of rules as the core sees them: lists of segments. */
|
|
2
|
+
import type { RawPattern } from "./core/index.ts";
|
|
3
|
+
/** What a target of a rule that is no file pattern has: its segments. */
|
|
4
|
+
interface Segmented {
|
|
5
|
+
readonly segments: RawPattern;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A file pattern as segments. `src/db/**` selects by path, `src/db/client.ts#query` names
|
|
9
|
+
* one export of a file, and `src/domain/order.ts#Order#total` one member of an export.
|
|
10
|
+
*/
|
|
11
|
+
export declare function filePattern(pattern: string): RawPattern;
|
|
12
|
+
/** A target as segments: a file pattern, or a package or a global. */
|
|
13
|
+
export declare function targetPattern(target: string | Segmented): RawPattern;
|
|
14
|
+
export {};
|
package/dist/patterns.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A file pattern as segments. `src/db/**` selects by path, `src/db/client.ts#query` names
|
|
3
|
+
* one export of a file, and `src/domain/order.ts#Order#total` one member of an export.
|
|
4
|
+
*/
|
|
5
|
+
export function filePattern(pattern) {
|
|
6
|
+
const hash = pattern.indexOf("#");
|
|
7
|
+
const file = (hash === -1 ? pattern : pattern.slice(0, hash)).replace(/^\.\//, "");
|
|
8
|
+
const segments = file.split("/");
|
|
9
|
+
const names = hash === -1 ? [] : pattern.slice(hash + 1).split("#");
|
|
10
|
+
return [...segments, ...names.map((name) => `#${name}`)];
|
|
11
|
+
}
|
|
12
|
+
/** A target as segments: a file pattern, or a package or a global. */
|
|
13
|
+
export function targetPattern(target) {
|
|
14
|
+
return typeof target === "string" ? filePattern(target) : target.segments;
|
|
15
|
+
}
|