@forumone/throughline-design-system 0.0.0 → 1.0.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +182 -0
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/bin/check-block-props.mjs +51 -0
- package/bin/stub-styles.mjs +28 -0
- package/dist/admin/BlockGuidance.d.ts +13 -0
- package/dist/admin/BlockGuidance.d.ts.map +1 -0
- package/dist/admin/BlockGuidance.js +13 -0
- package/dist/admin/BlockGuidance.js.map +1 -0
- package/dist/admin/BlockSummary.d.ts +10 -0
- package/dist/admin/BlockSummary.d.ts.map +1 -0
- package/dist/admin/BlockSummary.js +73 -0
- package/dist/admin/BlockSummary.js.map +1 -0
- package/dist/admin/RowSummary.d.ts +15 -0
- package/dist/admin/RowSummary.d.ts.map +1 -0
- package/dist/admin/RowSummary.js +16 -0
- package/dist/admin/RowSummary.js.map +1 -0
- package/dist/admin/summary.d.ts +18 -0
- package/dist/admin/summary.d.ts.map +1 -0
- package/dist/admin/summary.js +48 -0
- package/dist/admin/summary.js.map +1 -0
- package/dist/altText.d.ts +16 -0
- package/dist/altText.d.ts.map +1 -0
- package/dist/altText.js +54 -0
- package/dist/altText.js.map +1 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +12 -0
- package/dist/client.js.map +1 -0
- package/dist/contract/index.d.ts +5 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +4 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/lint.d.ts +38 -0
- package/dist/contract/lint.d.ts.map +1 -0
- package/dist/contract/lint.js +110 -0
- package/dist/contract/lint.js.map +1 -0
- package/dist/contract/loader.d.ts +49 -0
- package/dist/contract/loader.d.ts.map +1 -0
- package/dist/contract/loader.js +95 -0
- package/dist/contract/loader.js.map +1 -0
- package/dist/contract/manifest.d.ts +454 -0
- package/dist/contract/manifest.d.ts.map +1 -0
- package/dist/contract/manifest.js +29 -0
- package/dist/contract/manifest.js.map +1 -0
- package/dist/contract/schema.d.ts +334 -0
- package/dist/contract/schema.d.ts.map +1 -0
- package/dist/contract/schema.js +224 -0
- package/dist/contract/schema.js.map +1 -0
- package/dist/generate/blocks.d.ts +79 -0
- package/dist/generate/blocks.d.ts.map +1 -0
- package/dist/generate/blocks.js +118 -0
- package/dist/generate/blocks.js.map +1 -0
- package/dist/generate/fields.d.ts +60 -0
- package/dist/generate/fields.d.ts.map +1 -0
- package/dist/generate/fields.js +478 -0
- package/dist/generate/fields.js.map +1 -0
- package/dist/generate/guidance.d.ts +5 -0
- package/dist/generate/guidance.d.ts.map +1 -0
- package/dist/generate/guidance.js +29 -0
- package/dist/generate/guidance.js.map +1 -0
- package/dist/generate/index.d.ts +13 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +9 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/generate/labels.d.ts +42 -0
- package/dist/generate/labels.d.ts.map +1 -0
- package/dist/generate/labels.js +226 -0
- package/dist/generate/labels.js.map +1 -0
- package/dist/generate/layout.d.ts +42 -0
- package/dist/generate/layout.d.ts.map +1 -0
- package/dist/generate/layout.js +252 -0
- package/dist/generate/layout.js.map +1 -0
- package/dist/generate/selectOptionSnapshot.d.ts +26 -0
- package/dist/generate/selectOptionSnapshot.d.ts.map +1 -0
- package/dist/generate/selectOptionSnapshot.js +47 -0
- package/dist/generate/selectOptionSnapshot.js.map +1 -0
- package/dist/generate/selectOptions.d.ts +64 -0
- package/dist/generate/selectOptions.d.ts.map +1 -0
- package/dist/generate/selectOptions.js +145 -0
- package/dist/generate/selectOptions.js.map +1 -0
- package/dist/overrides.d.ts +71 -0
- package/dist/overrides.d.ts.map +1 -0
- package/dist/overrides.js +16 -0
- package/dist/overrides.js.map +1 -0
- package/dist/render/RenderBlocks.d.ts +67 -0
- package/dist/render/RenderBlocks.d.ts.map +1 -0
- package/dist/render/RenderBlocks.js +31 -0
- package/dist/render/RenderBlocks.js.map +1 -0
- package/dist/render/coerce.d.ts +78 -0
- package/dist/render/coerce.d.ts.map +1 -0
- package/dist/render/coerce.js +243 -0
- package/dist/render/coerce.js.map +1 -0
- package/dist/render/index.d.ts +5 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +3 -0
- package/dist/render/index.js.map +1 -0
- package/dist/testing/checkBlockProps.d.ts +66 -0
- package/dist/testing/checkBlockProps.d.ts.map +1 -0
- package/dist/testing/checkBlockProps.js +241 -0
- package/dist/testing/checkBlockProps.js.map +1 -0
- package/dist/testing/checkBlockPropsCli.d.ts +12 -0
- package/dist/testing/checkBlockPropsCli.d.ts.map +1 -0
- package/dist/testing/checkBlockPropsCli.js +86 -0
- package/dist/testing/checkBlockPropsCli.js.map +1 -0
- package/dist/testing/contractDefaults.d.ts +21 -0
- package/dist/testing/contractDefaults.d.ts.map +1 -0
- package/dist/testing/contractDefaults.js +65 -0
- package/dist/testing/contractDefaults.js.map +1 -0
- package/dist/testing/describeBlockInvariants.d.ts +39 -0
- package/dist/testing/describeBlockInvariants.d.ts.map +1 -0
- package/dist/testing/describeBlockInvariants.js +71 -0
- package/dist/testing/describeBlockInvariants.js.map +1 -0
- package/dist/testing/index.d.ts +18 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +14 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/untouchedBlocks.d.ts +48 -0
- package/dist/testing/untouchedBlocks.d.ts.map +1 -0
- package/dist/testing/untouchedBlocks.js +155 -0
- package/dist/testing/untouchedBlocks.js.map +1 -0
- package/package.json +108 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { coerceBlock } from '../render/coerce.js';
|
|
5
|
+
/*
|
|
6
|
+
Does a contract describe the props its component takes?
|
|
7
|
+
|
|
8
|
+
Nothing else checks it. The first site on this package shipped a contract
|
|
9
|
+
declaring a project's `image` as a bare `image` field while the component read
|
|
10
|
+
`image.src` and `image.alt`. Coercion produced a URL string, both properties
|
|
11
|
+
came back `undefined`, and every project rendered an `<img>` with no `src` and
|
|
12
|
+
no `alt`. Every gate passed, each for a defensible reason: the story supplied
|
|
13
|
+
`{ src, alt }`, so it and the axe check were right; manifest validation does not
|
|
14
|
+
compare field types with props; and the renderer's registry is `any` at the
|
|
15
|
+
seam, which is the honest boundary between two generated shapes, so typecheck
|
|
16
|
+
compared nothing.
|
|
17
|
+
|
|
18
|
+
## How
|
|
19
|
+
|
|
20
|
+
Per component: build the data Payload would store for its contract, run it
|
|
21
|
+
through the real `coerceBlock` with the host's real overrides, and compare the
|
|
22
|
+
shape of each prop with the component's args file. The args file is the ground
|
|
23
|
+
truth because it is `satisfies <Name>Props` — TypeScript has already checked it
|
|
24
|
+
against the component — so a disagreement is between the contract and the
|
|
25
|
+
component, which is the thing being looked for.
|
|
26
|
+
|
|
27
|
+
## What it does not do
|
|
28
|
+
|
|
29
|
+
Only props in *both* the coerced output and the args are compared. Coercion adds
|
|
30
|
+
`<name>SrcSet` and `<name>Sizes` siblings no args file has; args carry code-only
|
|
31
|
+
props no contract has; and an optional field an args file does not exercise
|
|
32
|
+
cannot be compared with anything. Each of those is a legitimate absence, and a
|
|
33
|
+
shape mismatch needs both sides to describe the same prop.
|
|
34
|
+
*/
|
|
35
|
+
/** Marks a value the host rendered to React, so it is not read as a plain object. */
|
|
36
|
+
const NODE = Symbol('rendered-node');
|
|
37
|
+
const renderedNode = () => ({ [NODE]: true });
|
|
38
|
+
/**
|
|
39
|
+
* Real overrides, stubbed resolvers. Overrides change the *shape* — they omit
|
|
40
|
+
* fields, rename `body` to `children`, turn an icon name into a glyph — so they
|
|
41
|
+
* have to be the host's own. The resolvers turn an id into a URL or Lexical
|
|
42
|
+
* state into React; a stub produces the same shape as the real thing.
|
|
43
|
+
*/
|
|
44
|
+
export function stubCoerceContext(overrides = {}) {
|
|
45
|
+
return {
|
|
46
|
+
overrides,
|
|
47
|
+
resolveMedia: () => ({
|
|
48
|
+
url: 'https://example.invalid/image.webp',
|
|
49
|
+
alt: 'alt text',
|
|
50
|
+
width: 1200,
|
|
51
|
+
srcSet: 'https://example.invalid/image.webp 1200w',
|
|
52
|
+
sizes: '100vw',
|
|
53
|
+
}),
|
|
54
|
+
resolveHref: () => '/a-path',
|
|
55
|
+
renderRichText: renderedNode,
|
|
56
|
+
renderIcon: renderedNode,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** What Payload stores for a field of each type, filled in. */
|
|
60
|
+
export function storedValue(field) {
|
|
61
|
+
const objectOf = (fields) => {
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const child of fields)
|
|
64
|
+
out[child.name] = storedValue(child);
|
|
65
|
+
return out;
|
|
66
|
+
};
|
|
67
|
+
switch (field.type) {
|
|
68
|
+
case 'text':
|
|
69
|
+
case 'select':
|
|
70
|
+
return 'text';
|
|
71
|
+
case 'video':
|
|
72
|
+
return 'https://example.invalid/video.mp4';
|
|
73
|
+
case 'number':
|
|
74
|
+
return 1;
|
|
75
|
+
case 'boolean':
|
|
76
|
+
return true;
|
|
77
|
+
case 'richtext':
|
|
78
|
+
return { root: { type: 'root', children: [] } };
|
|
79
|
+
case 'link':
|
|
80
|
+
return { mode: 'external', url: 'https://example.invalid' };
|
|
81
|
+
case 'image':
|
|
82
|
+
return { id: 1, url: 'https://example.invalid/image.webp', alt: 'alt text' };
|
|
83
|
+
case 'group':
|
|
84
|
+
return field.of ? objectOf(field.of) : undefined;
|
|
85
|
+
case 'array':
|
|
86
|
+
// One row is enough to establish the row's shape.
|
|
87
|
+
return field.of ? [{ id: 'row-1', ...objectOf(field.of) }] : undefined;
|
|
88
|
+
default:
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** A whole block's stored data, for one component's fields. */
|
|
93
|
+
export function storedObject(fields) {
|
|
94
|
+
const out = {};
|
|
95
|
+
for (const field of fields)
|
|
96
|
+
out[field.name] = storedValue(field);
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
export function kindOf(value) {
|
|
100
|
+
if (value === undefined || value === null)
|
|
101
|
+
return 'absent';
|
|
102
|
+
if (Array.isArray(value))
|
|
103
|
+
return 'array';
|
|
104
|
+
if (typeof value === 'object') {
|
|
105
|
+
const held = value;
|
|
106
|
+
// The coerced side holds React through the stubs; the args side as JSX.
|
|
107
|
+
if (held[NODE] === true || '$$typeof' in held)
|
|
108
|
+
return 'node';
|
|
109
|
+
return 'object';
|
|
110
|
+
}
|
|
111
|
+
if (typeof value === 'string')
|
|
112
|
+
return 'string';
|
|
113
|
+
if (typeof value === 'number')
|
|
114
|
+
return 'number';
|
|
115
|
+
if (typeof value === 'boolean')
|
|
116
|
+
return 'boolean';
|
|
117
|
+
return 'object';
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Compare two values structurally, recording where they disagree. Recurses
|
|
121
|
+
* into objects and into the first element of an array, where a row's shape
|
|
122
|
+
* lives; depth-limited, because a contract nests no deeper than an array of
|
|
123
|
+
* groups and a cycle in an args file must not hang the check.
|
|
124
|
+
*/
|
|
125
|
+
export function compareShapes(component, prop, coerced, args, found, depth = 0) {
|
|
126
|
+
const a = kindOf(coerced);
|
|
127
|
+
const b = kindOf(args);
|
|
128
|
+
if (a === 'absent' || b === 'absent')
|
|
129
|
+
return;
|
|
130
|
+
/*
|
|
131
|
+
A string and a rendered node are interchangeable: a prop typed `ReactNode`
|
|
132
|
+
takes both, and an args *value* cannot say which the prop declares. The
|
|
133
|
+
mismatch this exists for — an object where a scalar was produced — is still
|
|
134
|
+
one.
|
|
135
|
+
*/
|
|
136
|
+
if ((a === 'string' && b === 'node') || (a === 'node' && b === 'string'))
|
|
137
|
+
return;
|
|
138
|
+
if (a !== b) {
|
|
139
|
+
found.push({ component, prop, coerced: a, args: b });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (depth >= 3)
|
|
143
|
+
return;
|
|
144
|
+
if (a === 'object') {
|
|
145
|
+
const left = coerced;
|
|
146
|
+
const right = args;
|
|
147
|
+
for (const key of Object.keys(left)) {
|
|
148
|
+
if (key in right)
|
|
149
|
+
compareShapes(component, `${prop}.${key}`, left[key], right[key], found, depth + 1);
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (a === 'array') {
|
|
154
|
+
const [left] = coerced;
|
|
155
|
+
const [right] = args;
|
|
156
|
+
if (left !== undefined && right !== undefined) {
|
|
157
|
+
compareShapes(component, `${prop}[]`, left, right, found, depth + 1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Coerce every component's contract and compare the props with its args. */
|
|
162
|
+
export async function checkBlockProps(options) {
|
|
163
|
+
const ctx = stubCoerceContext(options.overrides);
|
|
164
|
+
const result = { checked: [], skipped: [], mismatches: [] };
|
|
165
|
+
for (const [name, component] of Object.entries(options.manifest.components)) {
|
|
166
|
+
const args = await options.loadArgs(name);
|
|
167
|
+
if (!args) {
|
|
168
|
+
result.skipped.push(name);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const fields = component.content.fields ?? [];
|
|
172
|
+
const coerced = coerceBlock(name, fields, storedObject(fields), ctx);
|
|
173
|
+
for (const prop of Object.keys(coerced)) {
|
|
174
|
+
if (prop in args)
|
|
175
|
+
compareShapes(name, prop, coerced[prop], args[prop], result.mismatches);
|
|
176
|
+
}
|
|
177
|
+
result.checked.push(name);
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
const ARGS_EXTENSIONS = ['.ts', '.tsx', '.mts', '.js', '.mjs'];
|
|
182
|
+
/**
|
|
183
|
+
* Finds `<Name>/<name>args.<ext>` — the case is not guessed — in the first of
|
|
184
|
+
* `componentDirs` that has one, and returns its default export.
|
|
185
|
+
*
|
|
186
|
+
* TypeScript args files need a loader that understands them: the
|
|
187
|
+
* `check-block-props` bin registers `tsx`, and vitest transforms on its own.
|
|
188
|
+
*/
|
|
189
|
+
export function argsFileLoader(componentDirs) {
|
|
190
|
+
return async (component) => {
|
|
191
|
+
for (const root of componentDirs) {
|
|
192
|
+
const dir = path.join(root, component);
|
|
193
|
+
const entries = await readdir(dir).catch(() => []);
|
|
194
|
+
const file = entries.find(entry => {
|
|
195
|
+
const ext = path.extname(entry);
|
|
196
|
+
return (ARGS_EXTENSIONS.includes(ext) &&
|
|
197
|
+
entry.slice(0, -ext.length).toLowerCase() === `${component.toLowerCase()}args`);
|
|
198
|
+
});
|
|
199
|
+
if (!file)
|
|
200
|
+
continue;
|
|
201
|
+
const loaded = (await import(pathToFileURL(path.join(dir, file)).href));
|
|
202
|
+
const args = loaded.default;
|
|
203
|
+
return args && typeof args === 'object' ? args : undefined;
|
|
204
|
+
}
|
|
205
|
+
return undefined;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** The report a person reads, and whether it is a failure. */
|
|
209
|
+
export function formatBlockPropsResult(result) {
|
|
210
|
+
if (result.mismatches.length > 0) {
|
|
211
|
+
const lines = [
|
|
212
|
+
'',
|
|
213
|
+
` ${result.mismatches.length} contract/component mismatch(es).`,
|
|
214
|
+
'',
|
|
215
|
+
' A contract field produces a prop shape the component does not take. The',
|
|
216
|
+
' args file is `satisfies <Name>Props`, so it is the component that is right',
|
|
217
|
+
' and the contract that needs changing.',
|
|
218
|
+
'',
|
|
219
|
+
...result.mismatches.map(m => ` ${m.component}.${m.prop}: contract produces ${m.coerced}, component takes ${m.args}`),
|
|
220
|
+
'',
|
|
221
|
+
];
|
|
222
|
+
return { ok: false, text: lines.join('\n') };
|
|
223
|
+
}
|
|
224
|
+
if (result.checked.length === 0) {
|
|
225
|
+
return {
|
|
226
|
+
ok: false,
|
|
227
|
+
text: `No component had an args file, so nothing was compared ` +
|
|
228
|
+
`(${result.skipped.length} without one). Check the components directory, or that each ` +
|
|
229
|
+
`component has a <Name>Args.ts default-exporting its props.`,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
ok: true,
|
|
234
|
+
text: `Contracts agree with their components (${result.checked.length} checked` +
|
|
235
|
+
(result.skipped.length > 0
|
|
236
|
+
? `, ${result.skipped.length} without an args file: ${result.skipped.join(', ')}`
|
|
237
|
+
: '') +
|
|
238
|
+
').',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=checkBlockProps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkBlockProps.js","sourceRoot":"","sources":["../../src/testing/checkBlockProps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CliArgs {
|
|
2
|
+
manifest: string;
|
|
3
|
+
componentDirs: string[];
|
|
4
|
+
overrides?: string;
|
|
5
|
+
/** Applied by the bin when it registers tsx; recorded here so it parses. */
|
|
6
|
+
tsconfig?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Parse argv, or return the reason it cannot be. */
|
|
9
|
+
export declare function parseArgs(argv: readonly string[]): CliArgs | string;
|
|
10
|
+
/** Run the check; resolves to the process exit code. */
|
|
11
|
+
export declare function main(argv: readonly string[]): Promise<number>;
|
|
12
|
+
//# sourceMappingURL=checkBlockPropsCli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkBlockPropsCli.d.ts","sourceRoot":"","sources":["../../src/testing/checkBlockPropsCli.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,GAAG,MAAM,CA8BnE;AAcD,wDAAwD;AACxD,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBnE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* eslint-disable no-console -- a command-line tool: the console is its output. */
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { argsFileLoader, checkBlockProps, formatBlockPropsResult, } from './checkBlockProps.js';
|
|
6
|
+
const USAGE = `Usage: check-block-props <manifest.json> <components-dir> [<components-dir>...] [--overrides <module>] [--tsconfig <file>]
|
|
7
|
+
|
|
8
|
+
manifest.json the design system's built manifest
|
|
9
|
+
components-dir a directory holding one directory per component, each with a
|
|
10
|
+
<Name>Args.ts default-exporting props that satisfy <Name>Props.
|
|
11
|
+
Give several for a design system split across layers.
|
|
12
|
+
--overrides a module exporting the site's Overrides, as \`overrides\` or
|
|
13
|
+
default — the same object the generator and renderer use.
|
|
14
|
+
--tsconfig the tsconfig that compiles the args files, for its \`jsx\`
|
|
15
|
+
setting — e.g. a design system's tsconfig.app.json. Read by
|
|
16
|
+
the bin before anything loads; stylesheets are stubbed.`;
|
|
17
|
+
/** Parse argv, or return the reason it cannot be. */
|
|
18
|
+
export function parseArgs(argv) {
|
|
19
|
+
const positional = [];
|
|
20
|
+
let overrides;
|
|
21
|
+
let tsconfig;
|
|
22
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
23
|
+
const arg = argv[index];
|
|
24
|
+
if (arg === '--help' || arg === '-h')
|
|
25
|
+
return USAGE;
|
|
26
|
+
if (arg === '--overrides') {
|
|
27
|
+
overrides = argv[index + 1];
|
|
28
|
+
if (!overrides)
|
|
29
|
+
return `--overrides needs a module path.\n\n${USAGE}`;
|
|
30
|
+
index += 1;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (arg === '--tsconfig') {
|
|
34
|
+
tsconfig = argv[index + 1];
|
|
35
|
+
if (!tsconfig)
|
|
36
|
+
return `--tsconfig needs a file path.\n\n${USAGE}`;
|
|
37
|
+
index += 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (arg.startsWith('--'))
|
|
41
|
+
return `Unknown option ${arg}.\n\n${USAGE}`;
|
|
42
|
+
positional.push(arg);
|
|
43
|
+
}
|
|
44
|
+
const [manifest, ...componentDirs] = positional;
|
|
45
|
+
if (!manifest || componentDirs.length === 0)
|
|
46
|
+
return USAGE;
|
|
47
|
+
return {
|
|
48
|
+
manifest,
|
|
49
|
+
componentDirs,
|
|
50
|
+
...(overrides ? { overrides } : {}),
|
|
51
|
+
...(tsconfig ? { tsconfig } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function loadOverrides(file) {
|
|
55
|
+
const loaded = (await import(pathToFileURL(path.resolve(file)).href));
|
|
56
|
+
const overrides = loaded.overrides ?? loaded.default;
|
|
57
|
+
if (!overrides || typeof overrides !== 'object') {
|
|
58
|
+
throw new Error(`${file} exports no \`overrides\` (named or default).`);
|
|
59
|
+
}
|
|
60
|
+
return overrides;
|
|
61
|
+
}
|
|
62
|
+
/** Run the check; resolves to the process exit code. */
|
|
63
|
+
export async function main(argv) {
|
|
64
|
+
const args = parseArgs(argv);
|
|
65
|
+
if (typeof args === 'string') {
|
|
66
|
+
console.error(args);
|
|
67
|
+
return 2;
|
|
68
|
+
}
|
|
69
|
+
const manifest = JSON.parse(await readFile(path.resolve(args.manifest), 'utf8'));
|
|
70
|
+
if (!manifest.components || typeof manifest.components !== 'object') {
|
|
71
|
+
console.error(`${args.manifest} has no "components"; is it a design-system manifest?`);
|
|
72
|
+
return 2;
|
|
73
|
+
}
|
|
74
|
+
const result = await checkBlockProps({
|
|
75
|
+
manifest,
|
|
76
|
+
loadArgs: argsFileLoader(args.componentDirs.map(dir => path.resolve(dir))),
|
|
77
|
+
overrides: args.overrides ? await loadOverrides(args.overrides) : {},
|
|
78
|
+
});
|
|
79
|
+
const report = formatBlockPropsResult(result);
|
|
80
|
+
if (report.ok)
|
|
81
|
+
console.warn(report.text);
|
|
82
|
+
else
|
|
83
|
+
console.error(report.text);
|
|
84
|
+
return report.ok ? 0 : 1;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=checkBlockPropsCli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkBlockPropsCli.js","sourceRoot":"","sources":["../../src/testing/checkBlockPropsCli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Block } from 'payload';
|
|
2
|
+
import type { ContentField } from '../generate/fields.js';
|
|
3
|
+
/** A generated default that disagrees with the contract. */
|
|
4
|
+
export interface DefaultMismatch {
|
|
5
|
+
/** `Block.group.field` */
|
|
6
|
+
path: string;
|
|
7
|
+
/** What the contract says the default is. */
|
|
8
|
+
contract: unknown;
|
|
9
|
+
/** What the generated field will store. */
|
|
10
|
+
generated: unknown;
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Every generated default in one block that disagrees with its contract.
|
|
15
|
+
*
|
|
16
|
+
* Walks the contract, not the block: a field an override omits or retypes is
|
|
17
|
+
* the host's decision and is not reported, and fields the generator adds of its
|
|
18
|
+
* own — a link's mode and new-tab box — are not the contract's to declare.
|
|
19
|
+
*/
|
|
20
|
+
export declare function defaultMismatches(block: Block, contractFields: readonly ContentField[]): DefaultMismatch[];
|
|
21
|
+
//# sourceMappingURL=contractDefaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractDefaults.d.ts","sourceRoot":"","sources":["../../src/testing/contractDefaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,SAAS,CAAA;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAyCzD,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAA;IACjB,2CAA2C;IAC3C,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,SAAS,YAAY,EAAE,GACtC,eAAe,EAAE,CAEnB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const isNamed = (field) => 'name' in field && typeof field.name === 'string';
|
|
2
|
+
/**
|
|
3
|
+
* A field list's named fields, looking through presentational wrappers — the
|
|
4
|
+
* generator arranges fields into rows and collapsibles, which store nothing.
|
|
5
|
+
*/
|
|
6
|
+
function namedFields(fields) {
|
|
7
|
+
return fields.flatMap(field => {
|
|
8
|
+
if (isNamed(field))
|
|
9
|
+
return [field];
|
|
10
|
+
if (field.type === 'tabs')
|
|
11
|
+
return field.tabs.flatMap(tab => namedFields(tab.fields));
|
|
12
|
+
return 'fields' in field && Array.isArray(field.fields) ? namedFields(field.fields) : [];
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Every generated default in one block that disagrees with its contract.
|
|
17
|
+
*
|
|
18
|
+
* Walks the contract, not the block: a field an override omits or retypes is
|
|
19
|
+
* the host's decision and is not reported, and fields the generator adds of its
|
|
20
|
+
* own — a link's mode and new-tab box — are not the contract's to declare.
|
|
21
|
+
*/
|
|
22
|
+
export function defaultMismatches(block, contractFields) {
|
|
23
|
+
return walk(contractFields, block.fields, block.slug);
|
|
24
|
+
}
|
|
25
|
+
function walk(contractFields, generatedFields, path) {
|
|
26
|
+
const found = [];
|
|
27
|
+
const generated = namedFields(generatedFields);
|
|
28
|
+
for (const field of contractFields) {
|
|
29
|
+
const match = generated.find(candidate => candidate.name === field.name);
|
|
30
|
+
if (!match)
|
|
31
|
+
continue;
|
|
32
|
+
const here = `${path}.${field.name}`;
|
|
33
|
+
if (field.type === 'boolean' && match.type === 'checkbox') {
|
|
34
|
+
const expected = field.defaultValue ?? false;
|
|
35
|
+
if (match.defaultValue !== expected) {
|
|
36
|
+
found.push({
|
|
37
|
+
path: here,
|
|
38
|
+
contract: field.defaultValue,
|
|
39
|
+
generated: match.defaultValue,
|
|
40
|
+
message: `${here} starts ${String(match.defaultValue)} in the CMS, and its contract says ` +
|
|
41
|
+
`${field.defaultValue === undefined ? 'nothing, which means false' : String(field.defaultValue)}. ` +
|
|
42
|
+
`A checkbox is never undefined, so the component's own default never applies.`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Text only. A select's default is a choice among the component's own
|
|
47
|
+
// options, not copy, and the contract has no way to declare one yet.
|
|
48
|
+
if (field.type === 'text' &&
|
|
49
|
+
typeof match.defaultValue === 'string' &&
|
|
50
|
+
match.defaultValue !== '') {
|
|
51
|
+
found.push({
|
|
52
|
+
path: here,
|
|
53
|
+
contract: undefined,
|
|
54
|
+
generated: match.defaultValue,
|
|
55
|
+
message: `${here} has the string default "${match.defaultValue}": content nobody typed, ` +
|
|
56
|
+
`written into every block anybody adds.`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if ((field.type === 'group' || field.type === 'array') && field.of && 'fields' in match) {
|
|
60
|
+
found.push(...walk(field.of, match.fields, here));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return found;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=contractDefaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractDefaults.js","sourceRoot":"","sources":["../../src/testing/contractDefaults.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Block } from 'payload';
|
|
2
|
+
import type { GeneratedBlock, ManifestLike } from '../generate/blocks.js';
|
|
3
|
+
export interface BlockInvariantOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Where to find each block's contract when `blocks` are plain Payload
|
|
6
|
+
* blocks. Not needed for the `GeneratedBlock[]` that `generateBlocks`
|
|
7
|
+
* returns, which carry their contract.
|
|
8
|
+
*/
|
|
9
|
+
manifest?: ManifestLike;
|
|
10
|
+
/**
|
|
11
|
+
* The fewest blocks the list may hold. A manifest that failed to load would
|
|
12
|
+
* make every assertion vacuous, so set this near the library's real size.
|
|
13
|
+
* Defaults to 1.
|
|
14
|
+
*/
|
|
15
|
+
minBlocks?: number;
|
|
16
|
+
/** The suite's name. Defaults to "design-system block invariants". */
|
|
17
|
+
title?: string;
|
|
18
|
+
}
|
|
19
|
+
type BlockInput = Block | GeneratedBlock;
|
|
20
|
+
/**
|
|
21
|
+
* Registers a vitest suite asserting what every generated block must hold:
|
|
22
|
+
*
|
|
23
|
+
* - **Untouched blocks validate.** Every field `validate` passes the data
|
|
24
|
+
* Payload stores for a freshly-added block, and again with one empty row in
|
|
25
|
+
* every array.
|
|
26
|
+
* - **Contract defaults survive.** Every generated checkbox starts where its
|
|
27
|
+
* contract says, and no generated text field has a string default.
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { designSystemBlocks } from './index.js'
|
|
31
|
+
* describeBlockInvariants(designSystemBlocks, { manifest, minBlocks: 40 })
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* No database and no Payload instance: a block config is a value, and a
|
|
35
|
+
* `validate` is a function on it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function describeBlockInvariants(input: readonly BlockInput[], options?: BlockInvariantOptions): void;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=describeBlockInvariants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describeBlockInvariants.d.ts","sourceRoot":"","sources":["../../src/testing/describeBlockInvariants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAKzE,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,KAAK,UAAU,GAAG,KAAK,GAAG,cAAc,CAAA;AAKxC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,OAAO,GAAE,qBAA0B,GAClC,IAAI,CAiEN"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { defaultMismatches } from './contractDefaults.js';
|
|
3
|
+
import { runValidateCase, untouchedCases } from './untouchedBlocks.js';
|
|
4
|
+
const isGenerated = (input) => 'block' in input && 'component' in input;
|
|
5
|
+
/**
|
|
6
|
+
* Registers a vitest suite asserting what every generated block must hold:
|
|
7
|
+
*
|
|
8
|
+
* - **Untouched blocks validate.** Every field `validate` passes the data
|
|
9
|
+
* Payload stores for a freshly-added block, and again with one empty row in
|
|
10
|
+
* every array.
|
|
11
|
+
* - **Contract defaults survive.** Every generated checkbox starts where its
|
|
12
|
+
* contract says, and no generated text field has a string default.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { designSystemBlocks } from './index.js'
|
|
16
|
+
* describeBlockInvariants(designSystemBlocks, { manifest, minBlocks: 40 })
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* No database and no Payload instance: a block config is a value, and a
|
|
20
|
+
* `validate` is a function on it.
|
|
21
|
+
*/
|
|
22
|
+
export function describeBlockInvariants(input, options = {}) {
|
|
23
|
+
const blocks = input.map(item => (isGenerated(item) ? item.block : item));
|
|
24
|
+
const contracts = new Map();
|
|
25
|
+
for (const item of input) {
|
|
26
|
+
if (isGenerated(item))
|
|
27
|
+
contracts.set(item.block.slug, item.component.content.fields);
|
|
28
|
+
}
|
|
29
|
+
if (options.manifest) {
|
|
30
|
+
for (const block of blocks) {
|
|
31
|
+
const component = options.manifest.components[block.slug];
|
|
32
|
+
if (component && !contracts.has(block.slug))
|
|
33
|
+
contracts.set(block.slug, component.content.fields);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
describe(options.title ?? 'design-system block invariants', () => {
|
|
37
|
+
it('has the whole library, not an empty list', () => {
|
|
38
|
+
expect(blocks.length).toBeGreaterThanOrEqual(Math.max(1, options.minBlocks ?? 1));
|
|
39
|
+
});
|
|
40
|
+
for (const rows of ['none', 'one']) {
|
|
41
|
+
describe(`a block added and saved with ${rows === 'none' ? 'no array rows' : 'one empty array row'}`, () => {
|
|
42
|
+
const cases = untouchedCases(blocks, rows);
|
|
43
|
+
if (cases.length === 0) {
|
|
44
|
+
// Nothing to call is a fact worth seeing, not a failure: a library
|
|
45
|
+
// with no optional groups or links has no generated validate.
|
|
46
|
+
it.skip('no generated field carries a validate');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
it.each(cases.map(found => [found.path, found]))('%s validates', async (path, found) => {
|
|
50
|
+
const result = await runValidateCase(found);
|
|
51
|
+
expect(result, `${path} refuses an untouched block: "${String(result)}". An author would see that ` +
|
|
52
|
+
'on a block they have just added and not yet typed into.').toBe(true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
describe('contract defaults survive into the CMS', () => {
|
|
57
|
+
it('knows the contract of every block', () => {
|
|
58
|
+
const unknown = blocks.filter(block => !contracts.has(block.slug)).map(block => block.slug);
|
|
59
|
+
expect(unknown, 'pass the GeneratedBlock[] from generateBlocks, or the manifest as options.manifest').toEqual([]);
|
|
60
|
+
});
|
|
61
|
+
const withContracts = blocks.filter(block => contracts.has(block.slug));
|
|
62
|
+
if (withContracts.length === 0)
|
|
63
|
+
return;
|
|
64
|
+
it.each(withContracts.map(block => [block.slug, block]))('%s starts where its contract says', (_slug, block) => {
|
|
65
|
+
const mismatches = defaultMismatches(block, contracts.get(block.slug) ?? []);
|
|
66
|
+
expect(mismatches.map(mismatch => mismatch.message)).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=describeBlockInvariants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describeBlockInvariants.js","sourceRoot":"","sources":["../../src/testing/describeBlockInvariants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for a site's generated blocks, as
|
|
3
|
+
* `@forumone/throughline-design-system/testing`.
|
|
4
|
+
*
|
|
5
|
+
* Kept apart from the package root and `./generate`, which run inside
|
|
6
|
+
* `payload.config.ts`, because `describeBlockInvariants` imports `vitest` — an
|
|
7
|
+
* optional peer a running site never loads. The contract/component check is
|
|
8
|
+
* also a bin, `check-block-props`.
|
|
9
|
+
*/
|
|
10
|
+
export { describeBlockInvariants } from './describeBlockInvariants.js';
|
|
11
|
+
export type { BlockInvariantOptions } from './describeBlockInvariants.js';
|
|
12
|
+
export { checkUntouchedBlocks, untouchedData, validateCases, validateOptions, } from './untouchedBlocks.js';
|
|
13
|
+
export type { UntouchedFailure, UntouchedRows, ValidateCase } from './untouchedBlocks.js';
|
|
14
|
+
export { defaultMismatches } from './contractDefaults.js';
|
|
15
|
+
export type { DefaultMismatch } from './contractDefaults.js';
|
|
16
|
+
export { argsFileLoader, checkBlockProps, compareShapes, formatBlockPropsResult, kindOf, storedObject, storedValue, stubCoerceContext, } from './checkBlockProps.js';
|
|
17
|
+
export type { CheckBlockPropsOptions, CheckBlockPropsResult, PropKind, PropMismatch, PropsManifest, } from './checkBlockProps.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,YAAY,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACzE,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EACL,cAAc,EACd,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,MAAM,EACN,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,QAAQ,EACR,YAAY,EACZ,aAAa,GACd,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for a site's generated blocks, as
|
|
3
|
+
* `@forumone/throughline-design-system/testing`.
|
|
4
|
+
*
|
|
5
|
+
* Kept apart from the package root and `./generate`, which run inside
|
|
6
|
+
* `payload.config.ts`, because `describeBlockInvariants` imports `vitest` — an
|
|
7
|
+
* optional peer a running site never loads. The contract/component check is
|
|
8
|
+
* also a bin, `check-block-props`.
|
|
9
|
+
*/
|
|
10
|
+
export { describeBlockInvariants } from './describeBlockInvariants.js';
|
|
11
|
+
export { checkUntouchedBlocks, untouchedData, validateCases, validateOptions, } from './untouchedBlocks.js';
|
|
12
|
+
export { defaultMismatches } from './contractDefaults.js';
|
|
13
|
+
export { argsFileLoader, checkBlockProps, compareShapes, formatBlockPropsResult, kindOf, storedObject, storedValue, stubCoerceContext, } from './checkBlockProps.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAEtE,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD,OAAO,EACL,cAAc,EACd,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,MAAM,EACN,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,sBAAsB,CAAA"}
|