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.
Files changed (130) hide show
  1. package/dist/react/emoji/EmojiPicker.d.ts.map +1 -1
  2. package/dist/react/emoji/EmojiPicker.js +49 -8
  3. package/dist/react/emoji/EmojiPicker.js.map +1 -1
  4. package/dist/react/lib/form.d.ts +2 -2
  5. package/dist/react/lib/form.d.ts.map +1 -1
  6. package/dist/react/lib/form.js +4 -41
  7. package/dist/react/lib/form.js.map +1 -1
  8. package/dist/react/lib/zodResolver.d.ts +9 -0
  9. package/dist/react/lib/zodResolver.d.ts.map +1 -0
  10. package/dist/react/lib/zodResolver.js +105 -0
  11. package/dist/react/lib/zodResolver.js.map +1 -0
  12. package/dist/react/media/FocusViewer.d.ts.map +1 -1
  13. package/dist/react/media/FocusViewer.js.map +1 -1
  14. package/dist/react/media/MediaThumb.d.ts.map +1 -1
  15. package/dist/react/media/MediaThumb.js.map +1 -1
  16. package/dist/react/media/VideoTurner.d.ts.map +1 -1
  17. package/dist/react/media/VideoTurner.js.map +1 -1
  18. package/dist/react/media-gallery/GalleryTable.js.map +1 -1
  19. package/dist/react/media-gallery/MediaGallery.d.ts.map +1 -1
  20. package/dist/react/media-gallery/MediaGallery.js.map +1 -1
  21. package/dist/styles-areas/activity-bar.css +8 -11
  22. package/dist/styles-areas/analytics.css +30 -653
  23. package/dist/styles-areas/auth.css +10 -135
  24. package/dist/styles-areas/calendar.css +22 -397
  25. package/dist/styles-areas/chart-table.css +8 -20
  26. package/dist/styles-areas/charts.css +9 -70
  27. package/dist/styles-areas/chat.css +17 -345
  28. package/dist/styles-areas/clipboard.css +7 -7
  29. package/dist/styles-areas/code-editor.css +8 -111
  30. package/dist/styles-areas/companion-link.css +8 -51
  31. package/dist/styles-areas/core.css +131 -2488
  32. package/dist/styles-areas/dashboard-grid.css +10 -65
  33. package/dist/styles-areas/data-table.css +30 -638
  34. package/dist/styles-areas/deep-link.css +7 -7
  35. package/dist/styles-areas/diff-viewer.css +8 -11
  36. package/dist/styles-areas/disk-usage.css +13 -243
  37. package/dist/styles-areas/emoji.css +9 -135
  38. package/dist/styles-areas/fields.css +32 -563
  39. package/dist/styles-areas/file-tree.css +8 -14
  40. package/dist/styles-areas/filter-rail.css +14 -216
  41. package/dist/styles-areas/folder-tree.css +12 -200
  42. package/dist/styles-areas/keep-awake.css +7 -7
  43. package/dist/styles-areas/layout-engine.css +12 -220
  44. package/dist/styles-areas/markdown.css +9 -68
  45. package/dist/styles-areas/master-detail.css +14 -220
  46. package/dist/styles-areas/master-lock.css +9 -113
  47. package/dist/styles-areas/media-gallery.css +15 -332
  48. package/dist/styles-areas/media.css +20 -623
  49. package/dist/styles-areas/nav.css +24 -469
  50. package/dist/styles-areas/notifications.css +12 -226
  51. package/dist/styles-areas/overlays.css +14 -114
  52. package/dist/styles-areas/palette.css +15 -121
  53. package/dist/styles-areas/pdf-viewer.css +8 -28
  54. package/dist/styles-areas/problem-detail.css +9 -78
  55. package/dist/styles-areas/rich-text.css +9 -148
  56. package/dist/styles-areas/sharing.css +13 -134
  57. package/dist/styles-areas/spreadsheet.css +8 -18
  58. package/dist/styles-areas/stats.css +19 -262
  59. package/dist/styles-areas/test-report.css +13 -114
  60. package/dist/styles-areas/virtual.css +8 -11
  61. package/dist/styles-areas/wizard.css +21 -362
  62. package/dist/styles-areas/workbench.css +27 -524
  63. package/dist/styles-areas/workbook-viewer.css +8 -25
  64. package/dist/styles-static.css +1 -0
  65. package/dist/styles.css +1 -0
  66. package/package.json +23 -6
  67. package/scripts/checkAreaStyles.spec.ts +135 -1
  68. package/scripts/checkAreaStyles.ts +207 -6
  69. package/scripts/cssRules.ts +8 -1
  70. package/scripts/gate.ts +1 -1
  71. package/scripts/generateAreaStyles.ts +130 -10
  72. package/scripts/paths.ts +1 -1
  73. package/src/react/components/ActionBar.spec.tsx +1 -0
  74. package/src/react/emoji/EmojiPicker.tsx +70 -19
  75. package/src/react/file-tree/FileTree.tsx +3 -3
  76. package/src/react/lib/form.ts +5 -48
  77. package/src/react/lib/zodResolver.spec.ts +82 -0
  78. package/src/react/lib/zodResolver.ts +136 -0
  79. package/src/react/media/FocusViewer.tsx +1 -0
  80. package/src/react/media/MediaThumb.tsx +0 -1
  81. package/src/react/media/VideoTurner.tsx +0 -1
  82. package/src/react/media-gallery/GalleryTable.tsx +0 -1
  83. package/src/react/media-gallery/MediaGallery.tsx +0 -1
  84. package/src/styles-areas/activity-bar.css +8 -11
  85. package/src/styles-areas/analytics.css +30 -653
  86. package/src/styles-areas/auth.css +10 -135
  87. package/src/styles-areas/calendar.css +22 -397
  88. package/src/styles-areas/chart-table.css +8 -20
  89. package/src/styles-areas/charts.css +9 -70
  90. package/src/styles-areas/chat.css +17 -345
  91. package/src/styles-areas/clipboard.css +7 -7
  92. package/src/styles-areas/code-editor.css +8 -111
  93. package/src/styles-areas/companion-link.css +8 -51
  94. package/src/styles-areas/core.css +131 -2488
  95. package/src/styles-areas/dashboard-grid.css +10 -65
  96. package/src/styles-areas/data-table.css +30 -638
  97. package/src/styles-areas/deep-link.css +7 -7
  98. package/src/styles-areas/diff-viewer.css +8 -11
  99. package/src/styles-areas/disk-usage.css +13 -243
  100. package/src/styles-areas/emoji.css +9 -135
  101. package/src/styles-areas/fields.css +32 -563
  102. package/src/styles-areas/file-tree.css +8 -14
  103. package/src/styles-areas/filter-rail.css +14 -216
  104. package/src/styles-areas/folder-tree.css +12 -200
  105. package/src/styles-areas/keep-awake.css +7 -7
  106. package/src/styles-areas/layout-engine.css +12 -220
  107. package/src/styles-areas/markdown.css +9 -68
  108. package/src/styles-areas/master-detail.css +14 -220
  109. package/src/styles-areas/master-lock.css +9 -113
  110. package/src/styles-areas/media-gallery.css +15 -332
  111. package/src/styles-areas/media.css +20 -623
  112. package/src/styles-areas/nav.css +24 -469
  113. package/src/styles-areas/notifications.css +12 -226
  114. package/src/styles-areas/overlays.css +14 -114
  115. package/src/styles-areas/palette.css +15 -121
  116. package/src/styles-areas/pdf-viewer.css +8 -28
  117. package/src/styles-areas/problem-detail.css +9 -78
  118. package/src/styles-areas/rich-text.css +9 -148
  119. package/src/styles-areas/sharing.css +13 -134
  120. package/src/styles-areas/spreadsheet.css +8 -18
  121. package/src/styles-areas/stats.css +19 -262
  122. package/src/styles-areas/test-report.css +13 -114
  123. package/src/styles-areas/virtual.css +8 -11
  124. package/src/styles-areas/wizard.css +21 -362
  125. package/src/styles-areas/workbench.css +27 -524
  126. package/src/styles-areas/workbook-viewer.css +8 -25
  127. package/src/styles-static.css +1 -0
  128. package/src/styles.css +1 -0
  129. package/src/stylesAreas.spec.ts +12 -7
  130. 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
+ });