@ontrails/regrade 1.0.0-beta.41 → 1.0.0-beta.43
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/CHANGELOG.md +43 -0
- package/package.json +6 -6
- package/src/downstream/ast-rewrite.ts +37 -0
- package/src/downstream/collect.ts +12 -1
- package/src/downstream/export-restructure.ts +1 -1
- package/src/downstream/file-renames.ts +1590 -0
- package/src/downstream/report.ts +12 -1
- package/src/downstream/vocabulary-registry.ts +111 -12
- package/src/downstream/vocabulary.ts +631 -37
- package/src/index.ts +16 -0
- package/src/literal-transform.ts +1 -1
package/src/downstream/report.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from '@ontrails/core';
|
|
7
7
|
import type { ScanTargets } from '@ontrails/core';
|
|
8
8
|
import type {
|
|
9
|
+
GovernedVocabularyHistoryProvenance,
|
|
9
10
|
WardenDiagnostic,
|
|
10
11
|
WardenFixEdit,
|
|
11
12
|
WardenGuidance,
|
|
@@ -13,6 +14,7 @@ import type {
|
|
|
13
14
|
} from '@ontrails/warden';
|
|
14
15
|
import {
|
|
15
16
|
getWardenRuleMetadata,
|
|
17
|
+
governedVocabularyHistoryProvenanceSchema,
|
|
16
18
|
isWardenSourceScanTarget,
|
|
17
19
|
loadProjectWardenRules,
|
|
18
20
|
wardenRules,
|
|
@@ -756,7 +758,9 @@ export interface RegradeReport {
|
|
|
756
758
|
};
|
|
757
759
|
/** Saved applied Regrade history evidence for vocabulary regrades. */
|
|
758
760
|
readonly history?: {
|
|
761
|
+
readonly id?: string;
|
|
759
762
|
readonly path: string;
|
|
763
|
+
readonly provenance?: GovernedVocabularyHistoryProvenance;
|
|
760
764
|
readonly schemaVersion: number;
|
|
761
765
|
readonly status: 'applied' | 'checked' | 'replay';
|
|
762
766
|
};
|
|
@@ -1464,7 +1468,14 @@ export const regradeReportOutput = z.object({
|
|
|
1464
1468
|
),
|
|
1465
1469
|
history: z
|
|
1466
1470
|
.object({
|
|
1471
|
+
id: z
|
|
1472
|
+
.string()
|
|
1473
|
+
.optional()
|
|
1474
|
+
.describe('Stable consolidated Regrade history identity'),
|
|
1467
1475
|
path: z.string().describe('Root-relative applied history entry path'),
|
|
1476
|
+
provenance: governedVocabularyHistoryProvenanceSchema
|
|
1477
|
+
.optional()
|
|
1478
|
+
.describe('Governed transition evidence attached to the applied run'),
|
|
1468
1479
|
schemaVersion: z.number().describe('Regrade history schema version'),
|
|
1469
1480
|
status: z
|
|
1470
1481
|
.enum(['applied', 'checked', 'replay'])
|
|
@@ -1522,7 +1533,7 @@ export const regradeReportOutput = z.object({
|
|
|
1522
1533
|
/**
|
|
1523
1534
|
* Built-in regrade classes available to the report trail.
|
|
1524
1535
|
*
|
|
1525
|
-
* Warden owns term detection and fix metadata. Regrade
|
|
1536
|
+
* Warden owns term detection and fix metadata. Regrade derives Warden rules
|
|
1526
1537
|
* that advertise `term-rewrite` capability into reportable classes and then
|
|
1527
1538
|
* owns application/reporting of the resulting rewrite or review outcomes.
|
|
1528
1539
|
*/
|
|
@@ -31,12 +31,25 @@ const scopeFromTransition = (
|
|
|
31
31
|
return undefined;
|
|
32
32
|
}
|
|
33
33
|
return {
|
|
34
|
-
...(scope.exclude === undefined ? {} : { exclude: scope.exclude }),
|
|
35
|
-
...(scope.extensions === undefined
|
|
34
|
+
...(scope.exclude === undefined ? {} : { exclude: [...scope.exclude] }),
|
|
35
|
+
...(scope.extensions === undefined
|
|
36
|
+
? {}
|
|
37
|
+
: { extensions: [...scope.extensions] }),
|
|
36
38
|
...(scope.ignoredDirectories === undefined
|
|
37
39
|
? {}
|
|
38
|
-
: { ignoredDirectories: scope.ignoredDirectories }),
|
|
39
|
-
...(scope.include === undefined ? {} : { include: scope.include }),
|
|
40
|
+
: { ignoredDirectories: [...scope.ignoredDirectories] }),
|
|
41
|
+
...(scope.include === undefined ? {} : { include: [...scope.include] }),
|
|
42
|
+
...(scope.policyClassified === undefined
|
|
43
|
+
? {}
|
|
44
|
+
: {
|
|
45
|
+
policyClassified: scope.policyClassified.map((policy) => ({
|
|
46
|
+
...policy,
|
|
47
|
+
paths: [...policy.paths],
|
|
48
|
+
})),
|
|
49
|
+
}),
|
|
50
|
+
...(scope.teachingSurfaces === undefined
|
|
51
|
+
? {}
|
|
52
|
+
: { teachingSurfaces: [...scope.teachingSurfaces] }),
|
|
40
53
|
};
|
|
41
54
|
};
|
|
42
55
|
|
|
@@ -53,37 +66,122 @@ const defaultFormsAreRegistrySafe = (
|
|
|
53
66
|
});
|
|
54
67
|
};
|
|
55
68
|
|
|
69
|
+
const classifiedTargetMatches = (
|
|
70
|
+
transition: GovernedVocabularyTransition,
|
|
71
|
+
to: string
|
|
72
|
+
): boolean =>
|
|
73
|
+
transition.target.kind === 'classified' &&
|
|
74
|
+
transition.target.options.some((option) => option.to === to);
|
|
75
|
+
|
|
76
|
+
const uniqueForms = (forms: readonly string[]): readonly string[] => [
|
|
77
|
+
...new Set(forms),
|
|
78
|
+
];
|
|
79
|
+
|
|
56
80
|
export const vocabularyRegradePlanFromTransition = (
|
|
57
|
-
transition: GovernedVocabularyTransition
|
|
81
|
+
transition: GovernedVocabularyTransition,
|
|
82
|
+
classifiedTarget?: string
|
|
58
83
|
): VocabularyRegradePlan | null => {
|
|
84
|
+
const isClassifiedPlan =
|
|
85
|
+
classifiedTarget !== undefined &&
|
|
86
|
+
classifiedTargetMatches(transition, classifiedTarget);
|
|
87
|
+
if (transition.target.kind === 'classified' && !isClassifiedPlan) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
59
90
|
if (
|
|
60
|
-
transition.target.kind
|
|
91
|
+
transition.target.kind === 'single' &&
|
|
61
92
|
!defaultFormsAreRegistrySafe(transition)
|
|
62
93
|
) {
|
|
63
94
|
return null;
|
|
64
95
|
}
|
|
65
96
|
|
|
66
97
|
const scope = scopeFromTransition(transition);
|
|
98
|
+
const to =
|
|
99
|
+
transition.target.kind === 'single'
|
|
100
|
+
? transition.target.to
|
|
101
|
+
: classifiedTarget;
|
|
102
|
+
if (to === undefined) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
67
105
|
return {
|
|
68
106
|
caseSensitive: true,
|
|
69
|
-
deferForms:
|
|
107
|
+
deferForms: isClassifiedPlan
|
|
108
|
+
? uniqueForms([...transition.oldForms, ...transition.reviewForms])
|
|
109
|
+
: transition.reviewForms,
|
|
110
|
+
...(transition.fileRenames.length === 0
|
|
111
|
+
? {}
|
|
112
|
+
: {
|
|
113
|
+
fileRenames: transition.fileRenames.map((rename) => ({ ...rename })),
|
|
114
|
+
}),
|
|
70
115
|
from: transition.from,
|
|
71
116
|
id: transition.id,
|
|
72
117
|
intent: transition.intent,
|
|
73
118
|
kind: 'vocabulary',
|
|
74
|
-
overrides: transition.safeRewriteForms,
|
|
119
|
+
...(isClassifiedPlan ? {} : { overrides: transition.safeRewriteForms }),
|
|
75
120
|
preserve: preserveRulesFromTransition(transition),
|
|
76
121
|
...(scope === undefined ? {} : { scope }),
|
|
77
|
-
to
|
|
122
|
+
to,
|
|
78
123
|
};
|
|
79
124
|
};
|
|
80
125
|
|
|
126
|
+
export const vocabularyRegradePlanForInput = (
|
|
127
|
+
from: string,
|
|
128
|
+
to: string
|
|
129
|
+
): VocabularyRegradePlan | null => {
|
|
130
|
+
const transition = listGovernedVocabularyTransitions().find(
|
|
131
|
+
(candidate) => candidate.from === from
|
|
132
|
+
);
|
|
133
|
+
if (transition === undefined) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
if (transition.target.kind === 'single' && transition.target.to !== to) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return vocabularyRegradePlanFromTransition(transition, to);
|
|
140
|
+
};
|
|
141
|
+
|
|
81
142
|
export const listVocabularyRegradePlansFromRegistry =
|
|
82
143
|
(): readonly VocabularyRegradePlan[] =>
|
|
83
144
|
listGovernedVocabularyTransitions()
|
|
84
|
-
.map(vocabularyRegradePlanFromTransition)
|
|
145
|
+
.map((transition) => vocabularyRegradePlanFromTransition(transition))
|
|
85
146
|
.filter((plan): plan is VocabularyRegradePlan => plan !== null);
|
|
86
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Derive conservative current-tree audit plans for every single-target
|
|
150
|
+
* governed transition. Transitions that are unsafe to rewrite mechanically
|
|
151
|
+
* still participate with every known form deferred to review.
|
|
152
|
+
*/
|
|
153
|
+
export const listVocabularyRegradeAuditPlansFromRegistry =
|
|
154
|
+
(): readonly VocabularyRegradePlan[] =>
|
|
155
|
+
listGovernedVocabularyTransitions().flatMap((transition) => {
|
|
156
|
+
if (
|
|
157
|
+
transition.status === 'planned' ||
|
|
158
|
+
transition.target.kind !== 'single'
|
|
159
|
+
) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
const runnable = vocabularyRegradePlanFromTransition(transition);
|
|
163
|
+
if (runnable !== null) {
|
|
164
|
+
return [runnable];
|
|
165
|
+
}
|
|
166
|
+
const scope = scopeFromTransition(transition);
|
|
167
|
+
return [
|
|
168
|
+
{
|
|
169
|
+
caseSensitive: true,
|
|
170
|
+
deferForms: uniqueForms([
|
|
171
|
+
...transition.oldForms,
|
|
172
|
+
...transition.reviewForms,
|
|
173
|
+
]),
|
|
174
|
+
from: transition.from,
|
|
175
|
+
id: transition.id,
|
|
176
|
+
intent: transition.intent,
|
|
177
|
+
kind: 'vocabulary' as const,
|
|
178
|
+
preserve: preserveRulesFromTransition(transition),
|
|
179
|
+
...(scope === undefined ? {} : { scope }),
|
|
180
|
+
to: transition.target.to,
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
});
|
|
184
|
+
|
|
87
185
|
export const vocabularyRegradeTransitionForInput = (
|
|
88
186
|
from: string,
|
|
89
187
|
to: string
|
|
@@ -91,6 +189,7 @@ export const vocabularyRegradeTransitionForInput = (
|
|
|
91
189
|
listGovernedVocabularyTransitions().find(
|
|
92
190
|
(transition) =>
|
|
93
191
|
transition.from === from &&
|
|
94
|
-
transition.target.kind === 'single'
|
|
95
|
-
|
|
192
|
+
(transition.target.kind === 'single'
|
|
193
|
+
? transition.target.to === to
|
|
194
|
+
: transition.target.options.some((option) => option.to === to))
|
|
96
195
|
);
|