@goodbones/core 0.1.0-beta.10 → 0.1.0-beta.12
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/build/dts/core/structure.d.ts.map +1 -1
- package/build/dts/domain/architecture-config.d.ts +3 -310
- package/build/dts/domain/architecture-config.d.ts.map +1 -1
- package/build/dts/domain/snapshot.d.ts +150 -18
- package/build/dts/domain/snapshot.d.ts.map +1 -1
- package/build/dts/index.d.ts +11 -14
- package/build/dts/index.d.ts.map +1 -1
- package/build/dts/infrastructure/file-system-fake.d.ts.map +1 -1
- package/build/dts/infrastructure/file-system-live.d.ts.map +1 -1
- package/build/dts/infrastructure/walk.d.ts +6 -1
- package/build/dts/infrastructure/walk.d.ts.map +1 -1
- package/build/dts/load/extension.d.ts +33 -0
- package/build/dts/load/extension.d.ts.map +1 -0
- package/build/dts/load/policy.d.ts +4 -10
- package/build/dts/load/policy.d.ts.map +1 -1
- package/build/dts/manifest/compile.d.ts +7 -2
- package/build/dts/manifest/compile.d.ts.map +1 -1
- package/build/dts/manifest/extension.d.ts +8 -0
- package/build/dts/manifest/extension.d.ts.map +1 -0
- package/build/dts/manifest/glob.d.ts +1 -0
- package/build/dts/manifest/glob.d.ts.map +1 -1
- package/build/dts/manifest/json-schema.d.ts +6 -2
- package/build/dts/manifest/json-schema.d.ts.map +1 -1
- package/build/dts/manifest/manifest.d.ts +7 -362
- package/build/dts/manifest/manifest.d.ts.map +1 -1
- package/build/dts/ports/file-system.d.ts +1 -0
- package/build/dts/ports/file-system.d.ts.map +1 -1
- package/build/dts/testing.d.ts +0 -1
- package/build/dts/testing.d.ts.map +1 -1
- package/build/esm/core/structure.js +1 -1
- package/build/esm/core/structure.js.map +1 -1
- package/build/esm/domain/architecture-config.js +3 -136
- package/build/esm/domain/architecture-config.js.map +1 -1
- package/build/esm/domain/snapshot.js +55 -15
- package/build/esm/domain/snapshot.js.map +1 -1
- package/build/esm/index.js +16 -10
- package/build/esm/index.js.map +1 -1
- package/build/esm/infrastructure/file-system-fake.js +10 -0
- package/build/esm/infrastructure/file-system-fake.js.map +1 -1
- package/build/esm/infrastructure/file-system-live.js +9 -1
- package/build/esm/infrastructure/file-system-live.js.map +1 -1
- package/build/esm/infrastructure/walk.js +50 -4
- package/build/esm/infrastructure/walk.js.map +1 -1
- package/build/esm/load/extension.js +2 -0
- package/build/esm/load/extension.js.map +1 -0
- package/build/esm/load/policy.js +43 -116
- package/build/esm/load/policy.js.map +1 -1
- package/build/esm/manifest/compile.js +3 -182
- package/build/esm/manifest/compile.js.map +1 -1
- package/build/esm/manifest/extension.js +2 -0
- package/build/esm/manifest/extension.js.map +1 -0
- package/build/esm/manifest/glob.js +3 -0
- package/build/esm/manifest/glob.js.map +1 -1
- package/build/esm/manifest/json-schema.js +45 -11
- package/build/esm/manifest/json-schema.js.map +1 -1
- package/build/esm/manifest/manifest.js +56 -172
- package/build/esm/manifest/manifest.js.map +1 -1
- package/build/esm/testing.js +0 -1
- package/build/esm/testing.js.map +1 -1
- package/package.json +1 -1
- package/schema/architecture-node.schema.json +0 -887
- package/schema/architecture.schema.json +3264 -1591
- package/schema/conformance.schema.json +291 -47
- package/src/core/structure.ts +5 -3
- package/src/domain/architecture-config.ts +3 -180
- package/src/domain/snapshot.ts +125 -25
- package/src/index.ts +51 -78
- package/src/infrastructure/file-system-fake.ts +12 -0
- package/src/infrastructure/file-system-live.ts +8 -1
- package/src/infrastructure/walk.ts +58 -3
- package/src/load/extension.ts +66 -0
- package/src/load/policy.ts +60 -175
- package/src/manifest/compile.ts +2 -213
- package/src/manifest/extension.ts +41 -0
- package/src/manifest/glob.ts +5 -0
- package/src/manifest/json-schema.ts +53 -11
- package/src/manifest/manifest.ts +82 -214
- package/src/ports/file-system.ts +3 -0
- package/src/testing.ts +0 -1
- package/build/dts/core/campaigns.d.ts +0 -141
- package/build/dts/core/campaigns.d.ts.map +0 -1
- package/build/dts/core/ledger.d.ts +0 -61
- package/build/dts/core/ledger.d.ts.map +0 -1
- package/build/dts/domain/report.d.ts +0 -16
- package/build/dts/domain/report.d.ts.map +0 -1
- package/build/dts/infrastructure/campaign-functions.d.ts +0 -7
- package/build/dts/infrastructure/campaign-functions.d.ts.map +0 -1
- package/build/dts/infrastructure/report-source-fake.d.ts +0 -4
- package/build/dts/infrastructure/report-source-fake.d.ts.map +0 -1
- package/build/dts/infrastructure/report-source-live.d.ts +0 -3
- package/build/dts/infrastructure/report-source-live.d.ts.map +0 -1
- package/build/dts/ports/campaign-predicate.d.ts +0 -24
- package/build/dts/ports/campaign-predicate.d.ts.map +0 -1
- package/build/dts/ports/report-source.d.ts +0 -14
- package/build/dts/ports/report-source.d.ts.map +0 -1
- package/build/esm/core/campaigns.js +0 -778
- package/build/esm/core/campaigns.js.map +0 -1
- package/build/esm/core/ledger.js +0 -171
- package/build/esm/core/ledger.js.map +0 -1
- package/build/esm/domain/report.js +0 -168
- package/build/esm/domain/report.js.map +0 -1
- package/build/esm/infrastructure/campaign-functions.js +0 -67
- package/build/esm/infrastructure/campaign-functions.js.map +0 -1
- package/build/esm/infrastructure/report-source-fake.js +0 -6
- package/build/esm/infrastructure/report-source-fake.js.map +0 -1
- package/build/esm/infrastructure/report-source-live.js +0 -165
- package/build/esm/infrastructure/report-source-live.js.map +0 -1
- package/build/esm/ports/campaign-predicate.js +0 -2
- package/build/esm/ports/campaign-predicate.js.map +0 -1
- package/build/esm/ports/report-source.js +0 -7
- package/build/esm/ports/report-source.js.map +0 -1
- package/src/core/campaigns.ts +0 -1056
- package/src/core/ledger.ts +0 -242
- package/src/domain/report.ts +0 -203
- package/src/infrastructure/campaign-functions.ts +0 -98
- package/src/infrastructure/report-source-fake.ts +0 -10
- package/src/infrastructure/report-source-live.ts +0 -192
- package/src/ports/campaign-predicate.ts +0 -30
- package/src/ports/report-source.ts +0 -35
package/src/domain/snapshot.ts
CHANGED
|
@@ -18,7 +18,7 @@ import type { ViolationKind } from "./violation.js";
|
|
|
18
18
|
export const SNAPSHOT_SCHEMA_ID =
|
|
19
19
|
"https://dataquail.github.io/goodbones/schema/conformance.schema.json";
|
|
20
20
|
|
|
21
|
-
export const SNAPSHOT_VERSION =
|
|
21
|
+
export const SNAPSHOT_VERSION = 2;
|
|
22
22
|
|
|
23
23
|
const describe = <S extends Schema.Top>(schema: S, description: string) =>
|
|
24
24
|
schema.annotate({ description });
|
|
@@ -82,7 +82,16 @@ export const SnapshotViolation = Schema.Struct({
|
|
|
82
82
|
baselined: describe(Schema.Boolean, "Carried by the baseline, so `check` does not fail on it."),
|
|
83
83
|
ledgered: describe(
|
|
84
84
|
Schema.Boolean,
|
|
85
|
-
"For a campaign hit: carried by the
|
|
85
|
+
"For a campaign hit: carried by the objective's ledger, so `check` does not fail on it.",
|
|
86
|
+
),
|
|
87
|
+
objective: Schema.optionalKey(
|
|
88
|
+
describe(Schema.String, "For a campaign hit: the objective that fired."),
|
|
89
|
+
),
|
|
90
|
+
sector: Schema.optionalKey(
|
|
91
|
+
describe(Schema.String, "For a campaign hit: the sector the hit falls in."),
|
|
92
|
+
),
|
|
93
|
+
entry: Schema.optionalKey(
|
|
94
|
+
describe(Schema.String, "For a campaign hit: its ledger entry, relative to the sector's root."),
|
|
86
95
|
),
|
|
87
96
|
});
|
|
88
97
|
|
|
@@ -130,46 +139,134 @@ export const SnapshotVacancy = Schema.Struct({
|
|
|
130
139
|
),
|
|
131
140
|
});
|
|
132
141
|
|
|
133
|
-
// One
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
// One objective's burn-down: what its ledger says, summed over its sectors.
|
|
143
|
+
export const SnapshotObjective = Schema.Struct({
|
|
144
|
+
id: describe(
|
|
145
|
+
Schema.String,
|
|
146
|
+
"The objective's id; its ledger is `<ledger>/<campaign>/<objective>.json`.",
|
|
147
|
+
),
|
|
148
|
+
phase: describe(
|
|
149
|
+
Schema.NullOr(Schema.String),
|
|
150
|
+
"The phase naming the objective, or `null` for one no phase names — in window everywhere.",
|
|
140
151
|
),
|
|
141
|
-
initial: describe(Schema.Finite, "
|
|
152
|
+
initial: describe(Schema.Finite, "Holdouts recorded as each sector entered the window, summed."),
|
|
142
153
|
allowed: describe(
|
|
143
154
|
Schema.Finite,
|
|
144
|
-
"
|
|
155
|
+
"Holdouts added since by `objectives concede` or a re-baseline, each with a concession.",
|
|
145
156
|
),
|
|
146
|
-
count: describe(Schema.Finite, "
|
|
147
|
-
|
|
157
|
+
count: describe(Schema.Finite, "Holdouts in the ledger now, every sector summed."),
|
|
158
|
+
cleared: describe(
|
|
148
159
|
Schema.Finite,
|
|
149
|
-
"
|
|
160
|
+
"Holdouts removed by `objectives clear` because they stopped firing.",
|
|
161
|
+
),
|
|
162
|
+
closed: describe(
|
|
163
|
+
Schema.Finite,
|
|
164
|
+
"Holdouts still firing when a sector left the window — not progress.",
|
|
150
165
|
),
|
|
151
166
|
progress: describe(
|
|
152
167
|
Schema.Finite,
|
|
153
|
-
"`1 - count / (initial + allowed)`: how much of everything ever ledgered has been paid down.",
|
|
168
|
+
"`1 - count / (initial + allowed - closed)`: how much of everything ever ledgered has been paid down.",
|
|
154
169
|
),
|
|
155
|
-
|
|
156
|
-
Schema.String,
|
|
157
|
-
"When
|
|
170
|
+
lastCleared: describe(
|
|
171
|
+
Schema.NullOr(Schema.String),
|
|
172
|
+
"When a holdout last left the ledger, ISO 8601 — the stall clock's reading; `null` with no ledger.",
|
|
173
|
+
),
|
|
174
|
+
concessions: describe(Schema.Finite, "How many times a count was allowed to go up."),
|
|
175
|
+
complete: describe(Schema.Boolean, "No holdouts remain."),
|
|
176
|
+
ledgered: describe(
|
|
177
|
+
Schema.Boolean,
|
|
178
|
+
"Whether a ledger exists. An objective with none has been declared and not yet cleared.",
|
|
179
|
+
),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// One phase of the ladder, and how many sectors stand at it.
|
|
183
|
+
export const SnapshotPhase = Schema.Struct({
|
|
184
|
+
id: describe(Schema.String, "The phase's id."),
|
|
185
|
+
defined: describe(
|
|
186
|
+
Schema.Boolean,
|
|
187
|
+
"Whether the phase names criteria. An open phase has only an intent, and is last.",
|
|
188
|
+
),
|
|
189
|
+
sectors: describe(Schema.Finite, "How many sectors are derived to stand at this phase."),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// One sector: where it stands, and its residue toward its next phase.
|
|
193
|
+
export const SnapshotSector = Schema.Struct({
|
|
194
|
+
name: describe(Schema.String, "The sector's identity, as its perimeter names it."),
|
|
195
|
+
phase: describe(
|
|
196
|
+
Schema.NullOr(Schema.String),
|
|
197
|
+
"The phase the sector is derived to stand at, or `null` when it is past the last one.",
|
|
198
|
+
),
|
|
199
|
+
reached: describe(
|
|
200
|
+
Schema.NullOr(Schema.String),
|
|
201
|
+
"The furthest phase the sector's record says it has reached; `null` before its first `clear`.",
|
|
202
|
+
),
|
|
203
|
+
files: describe(Schema.Finite, "How many files the sector claims."),
|
|
204
|
+
residue: describe(
|
|
205
|
+
Schema.Record(Schema.String, Schema.Finite),
|
|
206
|
+
"One dimension per objective in window for the sector: its holdouts there, never summed.",
|
|
207
|
+
),
|
|
208
|
+
stalled: describe(
|
|
209
|
+
Schema.Boolean,
|
|
210
|
+
"Holdouts remain for the sector and nothing has been cleared, attested or noted within `staleAfter`.",
|
|
211
|
+
),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// One campaign: its objectives' burn-down, the distribution of its sectors
|
|
215
|
+
// over its phases, the legacy remainder, and what changed in its plan.
|
|
216
|
+
export const SnapshotCampaign = Schema.Struct({
|
|
217
|
+
id: describe(Schema.String, "The campaign's id; its ledgers are under `<ledger>/<id>/`."),
|
|
218
|
+
title: Schema.optionalKey(describe(Schema.String, "The campaign's title, when it states one.")),
|
|
219
|
+
owner: Schema.optionalKey(
|
|
220
|
+
describe(Schema.String, "Who is running the campaign, as the manifest names them."),
|
|
221
|
+
),
|
|
222
|
+
count: describe(Schema.Finite, "Holdouts across every objective and sector."),
|
|
223
|
+
progress: describe(
|
|
224
|
+
Schema.Finite,
|
|
225
|
+
"Cleared over everything ever ledgered, across the campaign's objectives.",
|
|
226
|
+
),
|
|
227
|
+
objectives: describe(Schema.Array(SnapshotObjective), "Every objective, in manifest order."),
|
|
228
|
+
phases: describe(
|
|
229
|
+
Schema.Array(SnapshotPhase),
|
|
230
|
+
"The ladder, in order, with how many sectors stand at each phase.",
|
|
231
|
+
),
|
|
232
|
+
sectors: describe(Schema.Array(SnapshotSector), "Every sector the perimeter births, by name."),
|
|
233
|
+
legacy: describe(
|
|
234
|
+
Schema.Struct({
|
|
235
|
+
files: describe(Schema.Finite, "Files in the scope no sector claims."),
|
|
236
|
+
holdouts: describe(
|
|
237
|
+
Schema.Finite,
|
|
238
|
+
"Holdouts in the legacy, under the first phase's objectives — where a holdout moved out of a sector lands.",
|
|
239
|
+
),
|
|
240
|
+
}),
|
|
241
|
+
"The unclaimed remainder of the scope, which stands at the first phase and is not a sink.",
|
|
242
|
+
),
|
|
243
|
+
plan: describe(
|
|
244
|
+
Schema.Struct({
|
|
245
|
+
refined: describe(
|
|
246
|
+
Schema.Array(Schema.String),
|
|
247
|
+
"Phases refined since the last `clear`: an open phase that gained criteria, or a new one. Free.",
|
|
248
|
+
),
|
|
249
|
+
changed: describe(
|
|
250
|
+
Schema.Array(Schema.String),
|
|
251
|
+
"Defined phases whose definition changed since the last `clear` — what a reviewer reads every time.",
|
|
252
|
+
),
|
|
253
|
+
unreceipted: describe(
|
|
254
|
+
Schema.Array(Schema.String),
|
|
255
|
+
"Changed phases carrying no new concession; `check` fails on them.",
|
|
256
|
+
),
|
|
257
|
+
}),
|
|
258
|
+
"What changed in the plan, refinements and changes apart.",
|
|
158
259
|
),
|
|
159
|
-
regressions: describe(Schema.Finite, "How many times the count was allowed to go up."),
|
|
160
260
|
stalled: describe(
|
|
161
261
|
Schema.Boolean,
|
|
162
|
-
"
|
|
262
|
+
"Holdouts remain and nothing has been cleared, attested or noted within the campaign's `staleAfter`.",
|
|
163
263
|
),
|
|
164
|
-
complete: describe(Schema.Boolean, "No
|
|
264
|
+
complete: describe(Schema.Boolean, "No holdouts remain in any objective."),
|
|
165
265
|
onComplete: describe(
|
|
166
266
|
Schema.Literals(["keep", "remove"]),
|
|
167
267
|
"What the manifest asks once complete: keep the campaign as a guard, or remove it.",
|
|
168
268
|
),
|
|
169
|
-
ledgered: describe(
|
|
170
|
-
Schema.Boolean,
|
|
171
|
-
"Whether a ledger exists. A campaign with none has been declared and not yet initialised.",
|
|
172
|
-
),
|
|
269
|
+
ledgered: describe(Schema.Boolean, "Whether every objective has a ledger."),
|
|
173
270
|
});
|
|
174
271
|
|
|
175
272
|
export const Snapshot = Schema.Struct({
|
|
@@ -271,6 +368,9 @@ export type SnapshotSlack = typeof SnapshotSlack.Type;
|
|
|
271
368
|
export type SnapshotConcentration = typeof SnapshotConcentration.Type;
|
|
272
369
|
export type SnapshotVacancy = typeof SnapshotVacancy.Type;
|
|
273
370
|
export type SnapshotCampaign = typeof SnapshotCampaign.Type;
|
|
371
|
+
export type SnapshotObjective = typeof SnapshotObjective.Type;
|
|
372
|
+
export type SnapshotPhase = typeof SnapshotPhase.Type;
|
|
373
|
+
export type SnapshotSector = typeof SnapshotSector.Type;
|
|
274
374
|
|
|
275
375
|
// Decodes a document some other run wrote — the base of a pull request, a
|
|
276
376
|
// stored one — refusing a key the shape does not declare, so a consumer never
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
// manifest into a policy. A host composes these with a language pack and the
|
|
4
4
|
// live file system; a language pack implements the ports. Nothing here names a
|
|
5
5
|
// language. The fakes are under `@goodbones/core/testing`.
|
|
6
|
+
//
|
|
7
|
+
// A family the core does not own — `campaigns`, in @goodbones/campaigns —
|
|
8
|
+
// arrives as a `PolicyExtension` the host passes to `loadPolicy`: it claims
|
|
9
|
+
// its own manifest keys, decodes them with its own codec, and reads its state
|
|
10
|
+
// back off `LoadedPolicy.extensions`. What such a family needs from here is
|
|
11
|
+
// exported deliberately: the glob primitives its lowering must match
|
|
12
|
+
// character for character, the pattern vocabulary its detectors share with
|
|
13
|
+
// the other families, and `lowerManifest` itself, which an `endState` runs a
|
|
14
|
+
// sector-relative tree through.
|
|
6
15
|
export {
|
|
7
16
|
type Baseline,
|
|
8
17
|
type BaselineFilter,
|
|
@@ -14,25 +23,6 @@ export {
|
|
|
14
23
|
staleEntriesOf,
|
|
15
24
|
unbaselined,
|
|
16
25
|
} from "./core/baseline.js";
|
|
17
|
-
export {
|
|
18
|
-
type CampaignHit,
|
|
19
|
-
type CampaignInput,
|
|
20
|
-
campaignsFailingTheirProbe,
|
|
21
|
-
campaignsSelecting,
|
|
22
|
-
compileCampaignRule,
|
|
23
|
-
compileCampaignRules,
|
|
24
|
-
type CompiledCampaign,
|
|
25
|
-
type CompiledDetector,
|
|
26
|
-
evaluateCampaign,
|
|
27
|
-
evaluateCampaigns,
|
|
28
|
-
explainCampaign,
|
|
29
|
-
type FailedProbe,
|
|
30
|
-
leafTermsOf,
|
|
31
|
-
matchKeyOf,
|
|
32
|
-
probeInputOf,
|
|
33
|
-
reportSpecsOf,
|
|
34
|
-
type TermAnswer,
|
|
35
|
-
} from "./core/campaigns.js";
|
|
36
26
|
export {
|
|
37
27
|
type Coverage,
|
|
38
28
|
type CoverageFamily,
|
|
@@ -83,27 +73,6 @@ export {
|
|
|
83
73
|
rulesSelecting,
|
|
84
74
|
type SelectedRule,
|
|
85
75
|
} from "./core/imports.js";
|
|
86
|
-
export {
|
|
87
|
-
allowed,
|
|
88
|
-
decodeLedger,
|
|
89
|
-
EMPTY_LEDGER,
|
|
90
|
-
entryOf,
|
|
91
|
-
isComplete,
|
|
92
|
-
isStalled,
|
|
93
|
-
type Ledger,
|
|
94
|
-
ledgerArithmeticHolds,
|
|
95
|
-
ledgerOf,
|
|
96
|
-
Ledger as LedgerSchema,
|
|
97
|
-
newEntriesOf,
|
|
98
|
-
progressOf,
|
|
99
|
-
pruned,
|
|
100
|
-
reconcile,
|
|
101
|
-
type Reconciliation,
|
|
102
|
-
type Regression,
|
|
103
|
-
type RegressionRecord,
|
|
104
|
-
serializeLedger,
|
|
105
|
-
staleEntriesOf as staleLedgerEntriesOf,
|
|
106
|
-
} from "./core/ledger.js";
|
|
107
76
|
export {
|
|
108
77
|
type CompiledMemberRule,
|
|
109
78
|
compileMemberRules,
|
|
@@ -111,6 +80,16 @@ export {
|
|
|
111
80
|
memberRulesFailingTheirProbe,
|
|
112
81
|
memberRulesSelecting,
|
|
113
82
|
} from "./core/members.js";
|
|
83
|
+
export {
|
|
84
|
+
compilePatterns,
|
|
85
|
+
firstFromMatch,
|
|
86
|
+
matchesAny,
|
|
87
|
+
type Selectable,
|
|
88
|
+
sourcesOf,
|
|
89
|
+
targetAllowed,
|
|
90
|
+
type Targeted,
|
|
91
|
+
validateTargetPatterns,
|
|
92
|
+
} from "./core/patterns.js";
|
|
114
93
|
export {
|
|
115
94
|
type Concentration,
|
|
116
95
|
type ObservedEdge,
|
|
@@ -124,6 +103,7 @@ export {
|
|
|
124
103
|
EMPTY_STRUCTURE,
|
|
125
104
|
evaluateStructure,
|
|
126
105
|
requiredSiblingsOf,
|
|
106
|
+
siblingsOf,
|
|
127
107
|
structureRulesFailingTheirProbe,
|
|
128
108
|
} from "./core/structure.js";
|
|
129
109
|
export {
|
|
@@ -135,12 +115,8 @@ export {
|
|
|
135
115
|
} from "./core/surface.js";
|
|
136
116
|
export {
|
|
137
117
|
type Allowance,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
type CampaignRule,
|
|
141
|
-
type CampaignUnit,
|
|
142
|
-
type DeclarationKind,
|
|
143
|
-
type Detector,
|
|
118
|
+
BindingKind,
|
|
119
|
+
DeclarationKind,
|
|
144
120
|
type ExportFix,
|
|
145
121
|
type ExportRule,
|
|
146
122
|
type GraphConfig,
|
|
@@ -148,11 +124,11 @@ export {
|
|
|
148
124
|
type GraphOrphanRule,
|
|
149
125
|
type GraphReachRule,
|
|
150
126
|
type ImportProbe,
|
|
151
|
-
|
|
127
|
+
ImportProbeTarget,
|
|
152
128
|
type ImportRule,
|
|
153
129
|
type MemberRule,
|
|
154
|
-
|
|
155
|
-
|
|
130
|
+
MemberSubject,
|
|
131
|
+
PatternList,
|
|
156
132
|
type ResolveConfig,
|
|
157
133
|
type ResolveScope,
|
|
158
134
|
type StructureConfig,
|
|
@@ -177,14 +153,6 @@ export {
|
|
|
177
153
|
type ManifestPosition,
|
|
178
154
|
renderManifestPath,
|
|
179
155
|
} from "./domain/manifest-location.js";
|
|
180
|
-
export {
|
|
181
|
-
type Diagnostic,
|
|
182
|
-
indexByFile,
|
|
183
|
-
parseReport,
|
|
184
|
-
type ParseReportOptions,
|
|
185
|
-
type ReportFormat,
|
|
186
|
-
uniqueDiagnostics,
|
|
187
|
-
} from "./domain/report.js";
|
|
188
156
|
export {
|
|
189
157
|
CONFORMANCE_MEASURES,
|
|
190
158
|
type ConformanceMeasure,
|
|
@@ -195,7 +163,10 @@ export {
|
|
|
195
163
|
type SnapshotCampaign,
|
|
196
164
|
type SnapshotConcentration,
|
|
197
165
|
snapshotJsonSchema,
|
|
166
|
+
type SnapshotObjective,
|
|
167
|
+
type SnapshotPhase,
|
|
198
168
|
Snapshot as SnapshotSchema,
|
|
169
|
+
type SnapshotSector,
|
|
199
170
|
type SnapshotSlack,
|
|
200
171
|
type SnapshotVacancy,
|
|
201
172
|
type SnapshotViolation,
|
|
@@ -206,10 +177,6 @@ export {
|
|
|
206
177
|
type Violation,
|
|
207
178
|
type ViolationKind,
|
|
208
179
|
} from "./domain/violation.js";
|
|
209
|
-
export {
|
|
210
|
-
loadCampaignFunctions,
|
|
211
|
-
type LoadedCampaignFunctions,
|
|
212
|
-
} from "./infrastructure/campaign-functions.js";
|
|
213
180
|
export { makeFileSystemLive } from "./infrastructure/file-system-live.js";
|
|
214
181
|
export {
|
|
215
182
|
findManifestFile,
|
|
@@ -224,16 +191,25 @@ export {
|
|
|
224
191
|
type IncludeReader,
|
|
225
192
|
type SourceDocument,
|
|
226
193
|
} from "./infrastructure/manifest-include.js";
|
|
227
|
-
export { makeReportSourceLive } from "./infrastructure/report-source-live.js";
|
|
228
194
|
export {
|
|
229
195
|
listPackageRoots,
|
|
230
196
|
listSourceFiles,
|
|
197
|
+
listWorkspaceProjects,
|
|
231
198
|
type PackagedLanguage,
|
|
232
199
|
type PackageRoot,
|
|
233
200
|
type WalkedLanguage,
|
|
201
|
+
type WorkspaceProject,
|
|
234
202
|
} from "./infrastructure/walk.js";
|
|
203
|
+
export {
|
|
204
|
+
type ExtensionContext,
|
|
205
|
+
type ExtensionRoute,
|
|
206
|
+
type LoadedExtension,
|
|
207
|
+
type PolicyExtension,
|
|
208
|
+
} from "./load/extension.js";
|
|
235
209
|
export { type LoadedPolicy, loadPolicy, type LoadPolicyInput } from "./load/policy.js";
|
|
236
210
|
export {
|
|
211
|
+
CONVENTIONS,
|
|
212
|
+
expandAliases,
|
|
237
213
|
type LoweredRules,
|
|
238
214
|
lowerManifest,
|
|
239
215
|
type LowerOptions,
|
|
@@ -247,6 +223,15 @@ export {
|
|
|
247
223
|
originOf,
|
|
248
224
|
type Substitution,
|
|
249
225
|
} from "./manifest/expand.js";
|
|
226
|
+
export { type ManifestExtension } from "./manifest/extension.js";
|
|
227
|
+
export {
|
|
228
|
+
anchored,
|
|
229
|
+
type CaptureIndex,
|
|
230
|
+
type GlobCompilation,
|
|
231
|
+
globToRegExp,
|
|
232
|
+
globToRegexSource,
|
|
233
|
+
prefixed,
|
|
234
|
+
} from "./manifest/glob.js";
|
|
250
235
|
export {
|
|
251
236
|
type Candidate,
|
|
252
237
|
candidatesOf,
|
|
@@ -263,26 +248,20 @@ export {
|
|
|
263
248
|
MANIFEST_NODE_SCHEMA_ID,
|
|
264
249
|
MANIFEST_SCHEMA_ID,
|
|
265
250
|
manifestJsonSchema,
|
|
251
|
+
type ManifestJsonSchemaOptions,
|
|
266
252
|
manifestNodeJsonSchema,
|
|
267
253
|
} from "./manifest/json-schema.js";
|
|
268
254
|
export {
|
|
269
|
-
type CampaignSpec,
|
|
270
255
|
type DecodedManifest,
|
|
271
256
|
decodeManifest,
|
|
272
257
|
type DecodeManifestOptions,
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
durationMs,
|
|
258
|
+
decodeManifestTree,
|
|
259
|
+
globsOf,
|
|
276
260
|
type Manifest,
|
|
277
261
|
type ManifestNode,
|
|
278
262
|
Manifest as ManifestSchema,
|
|
263
|
+
SurfaceConvention,
|
|
279
264
|
} from "./manifest/manifest.js";
|
|
280
|
-
export {
|
|
281
|
-
type CampaignPredicate,
|
|
282
|
-
type CampaignPredicateInput,
|
|
283
|
-
type CampaignSubject,
|
|
284
|
-
type Range,
|
|
285
|
-
} from "./ports/campaign-predicate.js";
|
|
286
265
|
export { type FactExtractor } from "./ports/fact-extractor.js";
|
|
287
266
|
export { type FileSystem } from "./ports/file-system.js";
|
|
288
267
|
export { type Language } from "./ports/language.js";
|
|
@@ -291,12 +270,6 @@ export {
|
|
|
291
270
|
type ModuleResolver,
|
|
292
271
|
type ResolvedTarget,
|
|
293
272
|
} from "./ports/module-resolver.js";
|
|
294
|
-
export {
|
|
295
|
-
NO_REPORTS,
|
|
296
|
-
type ReportSource,
|
|
297
|
-
reportSourcesOf,
|
|
298
|
-
type ReportSpec,
|
|
299
|
-
} from "./ports/report-source.js";
|
|
300
273
|
export {
|
|
301
274
|
type Position,
|
|
302
275
|
type SyntaxMatch,
|
|
@@ -10,5 +10,17 @@ export const makeFileSystemFake = (
|
|
|
10
10
|
return {
|
|
11
11
|
exists: (repoRelativePath) => paths.has(repoRelativePath),
|
|
12
12
|
readText: (repoRelativePath) => contents[repoRelativePath] ?? null,
|
|
13
|
+
list: (repoRelativeDir) => {
|
|
14
|
+
const prefix = repoRelativeDir === "" ? "" : `${repoRelativeDir}/`;
|
|
15
|
+
return [
|
|
16
|
+
...new Set(
|
|
17
|
+
[...paths]
|
|
18
|
+
.filter((one) => one.startsWith(prefix))
|
|
19
|
+
.map((one) => one.slice(prefix.length).split("/")[0] ?? ""),
|
|
20
|
+
),
|
|
21
|
+
]
|
|
22
|
+
.filter((one) => one !== "")
|
|
23
|
+
.sort();
|
|
24
|
+
},
|
|
13
25
|
};
|
|
14
26
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
|
|
4
4
|
import type { FileSystem } from "../ports/file-system.js";
|
|
@@ -23,5 +23,12 @@ export const makeFileSystemLive = (repoRoot: string): FileSystem => {
|
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
|
+
list: (repoRelativeDir) => {
|
|
27
|
+
try {
|
|
28
|
+
return readdirSync(path.resolve(repoRoot, repoRelativeDir)).sort();
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
},
|
|
26
33
|
};
|
|
27
34
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
|
|
4
4
|
import type { Language } from "../ports/language.js";
|
|
@@ -24,13 +24,16 @@ export type WalkedLanguage = Pick<Language, "extensions" | "ignoredFiles">;
|
|
|
24
24
|
// Which files count as source is the languages' to say: the extension set is
|
|
25
25
|
// the union of theirs, and so is the set of files to step over. A root that
|
|
26
26
|
// names a file is that file, whatever its extension — `architecture check
|
|
27
|
-
// <file>` is a reasonable thing to type.
|
|
27
|
+
// <file>` is a reasonable thing to type. `widened` adds the extensions a
|
|
28
|
+
// campaign's scope names beyond the packs' — a file the pack cannot parse
|
|
29
|
+
// contributes no facts, and only a campaign that asked for it sees it.
|
|
28
30
|
export const listSourceFiles = (
|
|
29
31
|
repoRoot: string,
|
|
30
32
|
roots: ReadonlyArray<string>,
|
|
31
33
|
languages: ReadonlyArray<WalkedLanguage>,
|
|
34
|
+
widened: ReadonlyArray<string> = [],
|
|
32
35
|
): ReadonlyArray<string> => {
|
|
33
|
-
const extensions = new Set(languages.flatMap((language) => language.extensions));
|
|
36
|
+
const extensions = new Set([...languages.flatMap((language) => language.extensions), ...widened]);
|
|
34
37
|
const ignored = languages.flatMap((language) => language.ignoredFiles);
|
|
35
38
|
const isSource = (entry: string): boolean =>
|
|
36
39
|
extensions.has(path.extname(entry)) && !ignored.some((pattern) => pattern.test(entry));
|
|
@@ -121,3 +124,55 @@ export const listPackageRoots = (
|
|
|
121
124
|
}
|
|
122
125
|
return [...found.values()].sort((a, b) => a.root.localeCompare(b.root));
|
|
123
126
|
};
|
|
127
|
+
|
|
128
|
+
export type WorkspaceProject = {
|
|
129
|
+
readonly name: string;
|
|
130
|
+
// Repo-relative folder with forward slashes.
|
|
131
|
+
readonly root: string;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// The workspace's projects, for an `nx` perimeter: every folder under the
|
|
135
|
+
// roots holding a `project.json`, named by it — or, when it names nothing,
|
|
136
|
+
// by the `package.json` beside it, or the folder. Read from the files
|
|
137
|
+
// rather than from `nx graph`, so no process is spawned and a checkout
|
|
138
|
+
// without the workspace's tooling installed still has its sectors.
|
|
139
|
+
export const listWorkspaceProjects = (
|
|
140
|
+
repoRoot: string,
|
|
141
|
+
roots: ReadonlyArray<string>,
|
|
142
|
+
): ReadonlyArray<WorkspaceProject> => {
|
|
143
|
+
const found: Array<WorkspaceProject> = [];
|
|
144
|
+
const nameIn = (absolute: string, file: string): string | null => {
|
|
145
|
+
try {
|
|
146
|
+
const parsed = JSON.parse(readFileSync(path.join(absolute, file), "utf8")) as unknown;
|
|
147
|
+
const name =
|
|
148
|
+
typeof parsed === "object" && parsed !== null
|
|
149
|
+
? (parsed as { readonly name?: unknown }).name
|
|
150
|
+
: undefined;
|
|
151
|
+
return typeof name === "string" && name !== "" ? name : null;
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const walk = (absolute: string): void => {
|
|
157
|
+
if (existsSync(path.join(absolute, "project.json"))) {
|
|
158
|
+
const root = path.relative(repoRoot, absolute).replaceAll(path.sep, "/");
|
|
159
|
+
found.push({
|
|
160
|
+
name:
|
|
161
|
+
nameIn(absolute, "project.json") ??
|
|
162
|
+
nameIn(absolute, "package.json") ??
|
|
163
|
+
path.basename(absolute),
|
|
164
|
+
root,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
for (const entry of readdirSync(absolute)) {
|
|
168
|
+
if (SKIPPED.has(entry)) continue;
|
|
169
|
+
const child = path.join(absolute, entry);
|
|
170
|
+
if (statSync(child).isDirectory()) walk(child);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
for (const root of roots) {
|
|
174
|
+
const absolute = path.resolve(repoRoot, root);
|
|
175
|
+
if (statSync(absolute).isDirectory()) walk(absolute);
|
|
176
|
+
}
|
|
177
|
+
return found.sort((a, b) => a.root.localeCompare(b.root));
|
|
178
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type * as Result from "effect/Result";
|
|
2
|
+
|
|
3
|
+
import type { ResolveScope } from "../domain/architecture-config.js";
|
|
4
|
+
import type { ConfigInvalid, PatternInvalid } from "../domain/architecture-error.js";
|
|
5
|
+
import type { ManifestExtension } from "../manifest/extension.js";
|
|
6
|
+
import type { Manifest } from "../manifest/manifest.js";
|
|
7
|
+
import type { FactExtractor } from "../ports/fact-extractor.js";
|
|
8
|
+
import type { FileSystem } from "../ports/file-system.js";
|
|
9
|
+
import type { Language } from "../ports/language.js";
|
|
10
|
+
import type { SyntaxMatcher } from "../ports/syntax-matcher.js";
|
|
11
|
+
|
|
12
|
+
// The load half of a family the core does not own: what `loadPolicy` hands it,
|
|
13
|
+
// and what it hands back.
|
|
14
|
+
//
|
|
15
|
+
// A host composes the extensions it wants — `loadPolicy({ …, extensions: [
|
|
16
|
+
// campaignsExtension({ functions, reports }) ] })` — and reads its family's
|
|
17
|
+
// state back off `LoadedPolicy.extensions` through whatever typed accessor
|
|
18
|
+
// that package exports. The core carries the value and never looks inside it.
|
|
19
|
+
//
|
|
20
|
+
// An extension is given the same things the core's own families are given at
|
|
21
|
+
// load: the routing extractor and syntax matcher, the file system port, the
|
|
22
|
+
// language packs, and which scope covers a given file. It is not given the
|
|
23
|
+
// resolver, which is built after every rule has been probed — a family that
|
|
24
|
+
// needs one resolves at evaluation, off `LoadedPolicy`.
|
|
25
|
+
|
|
26
|
+
export type ExtensionRoute = {
|
|
27
|
+
readonly language: Language;
|
|
28
|
+
readonly scope: ResolveScope;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ExtensionContext<Spec = unknown> = {
|
|
32
|
+
// What this family's `decode` returned.
|
|
33
|
+
readonly spec: Spec;
|
|
34
|
+
readonly configPath: string;
|
|
35
|
+
readonly repoRoot: string;
|
|
36
|
+
// The manifest the core decoded — `resolve`, `aliases`, `tree`, the
|
|
37
|
+
// families the core owns. The family's own keys are in `spec`.
|
|
38
|
+
readonly config: Manifest;
|
|
39
|
+
readonly languages: ReadonlyArray<Language>;
|
|
40
|
+
readonly fileSystem: FileSystem;
|
|
41
|
+
// Routes each file to the extractor of the language whose scope covers it:
|
|
42
|
+
// the same one the core parsed its own probes with.
|
|
43
|
+
readonly extractor: FactExtractor;
|
|
44
|
+
// Routes each file to the syntax matcher of its scope's language; `parse`
|
|
45
|
+
// answers `null` for a language carrying none.
|
|
46
|
+
readonly syntax: SyntaxMatcher;
|
|
47
|
+
readonly routeFor: (file: string) => ExtensionRoute | undefined;
|
|
48
|
+
readonly now: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type LoadedExtension<Value = unknown> = {
|
|
52
|
+
// Carried on `LoadedPolicy.extensions`, keyed by the extension's id.
|
|
53
|
+
readonly value: Value;
|
|
54
|
+
// Rules of this family that do not report their own probe. Merged into the
|
|
55
|
+
// one refusal the loader raises for every family at once, so a vacuous
|
|
56
|
+
// campaign and a vacuous import rule are reported in the same sentence.
|
|
57
|
+
readonly vacuous?: ReadonlyArray<string> | undefined;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type PolicyExtension<Spec = unknown, Value = unknown> = ManifestExtension<Spec> & {
|
|
61
|
+
// A method, like `decode`, so the loader can hold every extension at one
|
|
62
|
+
// erased type after their specs have been decoded.
|
|
63
|
+
load(
|
|
64
|
+
context: ExtensionContext<Spec>,
|
|
65
|
+
): Result.Result<LoadedExtension<Value>, ConfigInvalid | PatternInvalid>;
|
|
66
|
+
};
|