cursedbelt 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/emoji/EmojiPicker.d.ts.map +1 -1
- package/dist/react/emoji/EmojiPicker.js +49 -8
- package/dist/react/emoji/EmojiPicker.js.map +1 -1
- package/dist/react/lib/form.d.ts +2 -2
- package/dist/react/lib/form.d.ts.map +1 -1
- package/dist/react/lib/form.js +4 -41
- package/dist/react/lib/form.js.map +1 -1
- package/dist/react/lib/zodResolver.d.ts +9 -0
- package/dist/react/lib/zodResolver.d.ts.map +1 -0
- package/dist/react/lib/zodResolver.js +105 -0
- package/dist/react/lib/zodResolver.js.map +1 -0
- package/dist/react/media/FocusViewer.d.ts.map +1 -1
- package/dist/react/media/FocusViewer.js.map +1 -1
- package/dist/react/media/MediaThumb.d.ts.map +1 -1
- package/dist/react/media/MediaThumb.js.map +1 -1
- package/dist/react/media/VideoTurner.d.ts.map +1 -1
- package/dist/react/media/VideoTurner.js.map +1 -1
- package/dist/react/media-gallery/GalleryTable.js.map +1 -1
- package/dist/react/media-gallery/MediaGallery.d.ts.map +1 -1
- package/dist/react/media-gallery/MediaGallery.js.map +1 -1
- package/dist/styles-areas/activity-bar.css +8 -11
- package/dist/styles-areas/analytics.css +30 -653
- package/dist/styles-areas/auth.css +10 -135
- package/dist/styles-areas/calendar.css +22 -397
- package/dist/styles-areas/chart-table.css +8 -20
- package/dist/styles-areas/charts.css +9 -70
- package/dist/styles-areas/chat.css +17 -345
- package/dist/styles-areas/clipboard.css +7 -7
- package/dist/styles-areas/code-editor.css +8 -111
- package/dist/styles-areas/companion-link.css +8 -51
- package/dist/styles-areas/core.css +131 -2488
- package/dist/styles-areas/dashboard-grid.css +10 -65
- package/dist/styles-areas/data-table.css +30 -638
- package/dist/styles-areas/deep-link.css +7 -7
- package/dist/styles-areas/diff-viewer.css +8 -11
- package/dist/styles-areas/disk-usage.css +13 -243
- package/dist/styles-areas/emoji.css +9 -135
- package/dist/styles-areas/fields.css +32 -563
- package/dist/styles-areas/file-tree.css +8 -14
- package/dist/styles-areas/filter-rail.css +14 -216
- package/dist/styles-areas/folder-tree.css +12 -200
- package/dist/styles-areas/keep-awake.css +7 -7
- package/dist/styles-areas/layout-engine.css +12 -220
- package/dist/styles-areas/markdown.css +9 -68
- package/dist/styles-areas/master-detail.css +14 -220
- package/dist/styles-areas/master-lock.css +9 -113
- package/dist/styles-areas/media-gallery.css +15 -332
- package/dist/styles-areas/media.css +20 -623
- package/dist/styles-areas/nav.css +24 -469
- package/dist/styles-areas/notifications.css +12 -226
- package/dist/styles-areas/overlays.css +14 -114
- package/dist/styles-areas/palette.css +15 -121
- package/dist/styles-areas/pdf-viewer.css +8 -28
- package/dist/styles-areas/problem-detail.css +9 -78
- package/dist/styles-areas/rich-text.css +9 -148
- package/dist/styles-areas/sharing.css +13 -134
- package/dist/styles-areas/spreadsheet.css +8 -18
- package/dist/styles-areas/stats.css +19 -262
- package/dist/styles-areas/test-report.css +13 -114
- package/dist/styles-areas/virtual.css +8 -11
- package/dist/styles-areas/wizard.css +21 -362
- package/dist/styles-areas/workbench.css +27 -524
- package/dist/styles-areas/workbook-viewer.css +8 -25
- package/dist/styles-static.css +1 -0
- package/dist/styles.css +1 -0
- package/package.json +23 -6
- package/scripts/checkAreaStyles.spec.ts +135 -1
- package/scripts/checkAreaStyles.ts +207 -6
- package/scripts/cssRules.ts +8 -1
- package/scripts/gate.ts +1 -1
- package/scripts/generateAreaStyles.ts +130 -10
- package/scripts/paths.ts +1 -1
- package/src/react/components/ActionBar.spec.tsx +1 -0
- package/src/react/emoji/EmojiPicker.tsx +70 -19
- package/src/react/file-tree/FileTree.tsx +3 -3
- package/src/react/lib/form.ts +5 -48
- package/src/react/lib/zodResolver.spec.ts +82 -0
- package/src/react/lib/zodResolver.ts +136 -0
- package/src/react/media/FocusViewer.tsx +1 -0
- package/src/react/media/MediaThumb.tsx +0 -1
- package/src/react/media/VideoTurner.tsx +0 -1
- package/src/react/media-gallery/GalleryTable.tsx +0 -1
- package/src/react/media-gallery/MediaGallery.tsx +0 -1
- package/src/styles-areas/activity-bar.css +8 -11
- package/src/styles-areas/analytics.css +30 -653
- package/src/styles-areas/auth.css +10 -135
- package/src/styles-areas/calendar.css +22 -397
- package/src/styles-areas/chart-table.css +8 -20
- package/src/styles-areas/charts.css +9 -70
- package/src/styles-areas/chat.css +17 -345
- package/src/styles-areas/clipboard.css +7 -7
- package/src/styles-areas/code-editor.css +8 -111
- package/src/styles-areas/companion-link.css +8 -51
- package/src/styles-areas/core.css +131 -2488
- package/src/styles-areas/dashboard-grid.css +10 -65
- package/src/styles-areas/data-table.css +30 -638
- package/src/styles-areas/deep-link.css +7 -7
- package/src/styles-areas/diff-viewer.css +8 -11
- package/src/styles-areas/disk-usage.css +13 -243
- package/src/styles-areas/emoji.css +9 -135
- package/src/styles-areas/fields.css +32 -563
- package/src/styles-areas/file-tree.css +8 -14
- package/src/styles-areas/filter-rail.css +14 -216
- package/src/styles-areas/folder-tree.css +12 -200
- package/src/styles-areas/keep-awake.css +7 -7
- package/src/styles-areas/layout-engine.css +12 -220
- package/src/styles-areas/markdown.css +9 -68
- package/src/styles-areas/master-detail.css +14 -220
- package/src/styles-areas/master-lock.css +9 -113
- package/src/styles-areas/media-gallery.css +15 -332
- package/src/styles-areas/media.css +20 -623
- package/src/styles-areas/nav.css +24 -469
- package/src/styles-areas/notifications.css +12 -226
- package/src/styles-areas/overlays.css +14 -114
- package/src/styles-areas/palette.css +15 -121
- package/src/styles-areas/pdf-viewer.css +8 -28
- package/src/styles-areas/problem-detail.css +9 -78
- package/src/styles-areas/rich-text.css +9 -148
- package/src/styles-areas/sharing.css +13 -134
- package/src/styles-areas/spreadsheet.css +8 -18
- package/src/styles-areas/stats.css +19 -262
- package/src/styles-areas/test-report.css +13 -114
- package/src/styles-areas/virtual.css +8 -11
- package/src/styles-areas/wizard.css +21 -362
- package/src/styles-areas/workbench.css +27 -524
- package/src/styles-areas/workbook-viewer.css +8 -25
- package/src/styles-static.css +1 -0
- package/src/styles.css +1 -0
- package/src/stylesAreas.spec.ts +12 -7
- package/src/unpeeredStaysOffTheBarrel.spec.ts +99 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔴 Nothing the `cursedbelt/react` barrel reaches may import an `unpeered` package — not
|
|
3
|
+
* statically, and not through a literal `import()` either.
|
|
4
|
+
*
|
|
5
|
+
* `unpeered` (task 2087) lists packages some subpaths use that are kept out of
|
|
6
|
+
* `peerDependencies` because npm cannot resolve their own peer ranges beside ours. That keeps
|
|
7
|
+
* `npm install cursedbelt` clean, and it has a price that `barrelsReachNoOptionalPeer.spec.ts`
|
|
8
|
+
* could not see: **a bundler resolves a literal `import()` at BUILD time, and Vite stubs a
|
|
9
|
+
* missing import only when it is a DECLARED optional peer.** 5.0.0 listed `@hookform/resolvers`
|
|
10
|
+
* and `@emoji-mart/react` there while `react/lib/form.ts` and `react/emoji/EmojiPicker.tsx`
|
|
11
|
+
* lazily imported them — lazy, so the static-only check above passed — and every app's
|
|
12
|
+
* clean-install `vite build` failed: `Rollup failed to resolve import "@hookform/resolvers/zod"`.
|
|
13
|
+
* Primary checkouts hid it for a day, because their `node_modules` still held the 4.x copies.
|
|
14
|
+
*
|
|
15
|
+
* 5.0.1 depends on neither (its own zod resolver; emoji-mart's `Picker` mounted directly). This
|
|
16
|
+
* spec is what keeps a third from arriving. The barrel is the subject because it is what every
|
|
17
|
+
* app imports; an opt-in subpath that needs glide (`./react/spreadsheet` and its two siblings) is
|
|
18
|
+
* named in `docs/API-REFERENCE.md`'s install table, and its consumer installs it on purpose.
|
|
19
|
+
* `tools/proveInstall.ts`'s consumer-bundle step is the same rule, proved against the PUBLISHED
|
|
20
|
+
* tarball in an empty directory.
|
|
21
|
+
*/
|
|
22
|
+
import { describe, expect, it } from 'bun:test';
|
|
23
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import pkg from '../package.json';
|
|
26
|
+
|
|
27
|
+
const REPO = fileURLToPath(new URL('..', import.meta.url));
|
|
28
|
+
const UNPEERED = Object.keys((pkg as { unpeered?: { packages?: Record<string, string> } }).unpeered?.packages ?? {});
|
|
29
|
+
|
|
30
|
+
/** `import x from "p"`, `export … from "p"`, `import "p"`, and — the 5.0.0 shape — `import("p")`. */
|
|
31
|
+
const ANY_SPECIFIER = /\bfrom\s*["']([^"'\n]+)["']|^\s*import\s*["']([^"'\n]+)["']|\bimport\(\s*["']([^"'\n]+)["']\s*\)/gm;
|
|
32
|
+
|
|
33
|
+
const packageOf = (specifier: string): string => {
|
|
34
|
+
const parts = specifier.split('/');
|
|
35
|
+
return (specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0]) ?? specifier;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Every package an entry's bundle names, static or dynamic, with all packages left external. */
|
|
39
|
+
function packagesReachedBy(entry: string, label: string): Set<string> {
|
|
40
|
+
const outdir = `${process.env.TMPDIR ?? '/tmp'}/cursedbelt-unpeered-scan-${process.pid}/${label}`;
|
|
41
|
+
rmSync(outdir, { recursive: true, force: true });
|
|
42
|
+
const build = Bun.spawnSync(['bun', 'build', entry, '--target=browser', '--packages=external', '--outdir', outdir], {
|
|
43
|
+
cwd: REPO,
|
|
44
|
+
stdout: 'pipe',
|
|
45
|
+
stderr: 'pipe',
|
|
46
|
+
});
|
|
47
|
+
const emitted = [...new Bun.Glob('**/*.js').scanSync({ cwd: outdir, onlyFiles: true })];
|
|
48
|
+
const bundle = emitted.map((f) => readFileSync(`${outdir}/${f}`, 'utf8')).join('\n');
|
|
49
|
+
if (build.exitCode !== 0 || bundle.trim() === '') {
|
|
50
|
+
throw new Error(`could not bundle ${entry} (exit ${build.exitCode}) — a check that cannot measure is not a passing check:\n${build.stderr.toString()}`);
|
|
51
|
+
}
|
|
52
|
+
const found = new Set<string>();
|
|
53
|
+
for (const m of bundle.matchAll(ANY_SPECIFIER)) {
|
|
54
|
+
const specifier = m[1] ?? m[2] ?? m[3];
|
|
55
|
+
if (specifier && !specifier.startsWith('.') && !specifier.startsWith('/')) found.add(packageOf(specifier));
|
|
56
|
+
}
|
|
57
|
+
return found;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
describe('unpeered packages stay off the cursedbelt/react barrel', () => {
|
|
61
|
+
it('🔴 the barrel names no unpeered package, even lazily', () => {
|
|
62
|
+
const source = (pkg.exports as Record<string, { source?: string }>)['./react']?.source;
|
|
63
|
+
expect(source, 'package.json has no ./react source entry').toBeString();
|
|
64
|
+
const reached = packagesReachedBy(`${REPO}${(source as string).slice(2)}`, 'barrel');
|
|
65
|
+
expect(reached.size, 'the scan found no packages at all — it is not measuring').toBeGreaterThan(0);
|
|
66
|
+
expect(
|
|
67
|
+
UNPEERED.filter((name) => reached.has(name)),
|
|
68
|
+
'the barrel imports an `unpeered` package. A consumer who did not install it cannot even BUILD: ' +
|
|
69
|
+
'Vite stubs only declared optional peers. Make it a declared optional peer, own the code, or ' +
|
|
70
|
+
'move the component to an opt-in subpath named in docs/API-REFERENCE.md.',
|
|
71
|
+
).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('`unpeered.subpaths` names only real opt-in subpaths, never the barrel, and only unpeered packages', () => {
|
|
75
|
+
// `tools/proveInstall.ts` excuses a fresh-install bundle failure ONLY for these pairs.
|
|
76
|
+
const subpaths = (pkg as { unpeered?: { subpaths?: Record<string, string[]> } }).unpeered?.subpaths ?? {};
|
|
77
|
+
expect(Object.keys(subpaths)).not.toContain('./react');
|
|
78
|
+
for (const [subpath, names] of Object.entries(subpaths)) {
|
|
79
|
+
expect(Object.keys(pkg.exports), `${subpath} is not an export`).toContain(subpath);
|
|
80
|
+
expect(names.filter((n) => !UNPEERED.includes(n)), `${subpath} names a package that is not unpeered`).toEqual([]);
|
|
81
|
+
}
|
|
82
|
+
// And every unpeered package is needed by at least one named subpath — or it is not needed.
|
|
83
|
+
const named = new Set(Object.values(subpaths).flat());
|
|
84
|
+
expect(UNPEERED.filter((n) => !named.has(n))).toEqual([]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('the scan sees a lazy import — 5.0.0 reproduced, so this check can go red', () => {
|
|
88
|
+
const dir = `${process.env.TMPDIR ?? '/tmp'}/cursedbelt-unpeered-fixture-${process.pid}`;
|
|
89
|
+
mkdirSync(dir, { recursive: true });
|
|
90
|
+
const entry = `${dir}/lazy.ts`;
|
|
91
|
+
writeFileSync(entry, "export const Picker = () => import('@emoji-mart/react');\nexport const zod = () => import('@hookform/resolvers/zod');\n");
|
|
92
|
+
try {
|
|
93
|
+
const reached = packagesReachedBy(entry, 'fixture');
|
|
94
|
+
expect([...reached].sort()).toEqual(['@emoji-mart/react', '@hookform/resolvers']);
|
|
95
|
+
} finally {
|
|
96
|
+
rmSync(dir, { recursive: true, force: true });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|