@usefragments/core 1.10.2 → 2.0.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/{chunk-MZ4SW3TP.js → chunk-3IOWHECM.js} +8 -1
  2. package/dist/{chunk-MZ4SW3TP.js.map → chunk-3IOWHECM.js.map} +1 -1
  3. package/dist/chunk-7ULGH74M.js +66 -0
  4. package/dist/chunk-7ULGH74M.js.map +1 -0
  5. package/dist/{chunk-XN3LSDPY.js → chunk-BMPYIUZE.js} +612 -344
  6. package/dist/chunk-BMPYIUZE.js.map +1 -0
  7. package/dist/{chunk-YF65VYRY.js → chunk-ML5S6QNU.js} +191 -169
  8. package/dist/chunk-ML5S6QNU.js.map +1 -0
  9. package/dist/{chunk-3LLRNCPX.js → chunk-MZ2FS7U4.js} +1 -1
  10. package/dist/chunk-MZ2FS7U4.js.map +1 -0
  11. package/dist/chunk-PWIJMOI4.js +202 -0
  12. package/dist/chunk-PWIJMOI4.js.map +1 -0
  13. package/dist/chunk-RYFULE43.js +578 -0
  14. package/dist/chunk-RYFULE43.js.map +1 -0
  15. package/dist/codes/index.d.ts +2 -2
  16. package/dist/codes/index.js +3 -2
  17. package/dist/compiled-types/index.d.ts +327 -2
  18. package/dist/compiled-types/index.js +1 -1
  19. package/dist/generate/index.d.ts +3 -2
  20. package/dist/{governance-CLk_wkP9.d.ts → governance-hOPXGbbs.d.ts} +474 -515
  21. package/dist/governance-telemetry.d.ts +6 -0
  22. package/dist/governance-telemetry.js +1 -1
  23. package/dist/{index-_sxhUNqx.d.ts → index-C8bcXVav.d.ts} +448 -448
  24. package/dist/index.d.ts +3280 -1305
  25. package/dist/index.js +2414 -350
  26. package/dist/index.js.map +1 -1
  27. package/dist/manifest.d.ts +228 -0
  28. package/dist/manifest.js +24 -0
  29. package/dist/manifest.js.map +1 -0
  30. package/dist/preview/index.js +45 -1
  31. package/dist/preview/index.js.map +1 -1
  32. package/dist/preview-runtime.d.ts +1 -2
  33. package/dist/preview-runtime.js +150 -14
  34. package/dist/preview-runtime.js.map +1 -1
  35. package/dist/react-types.d.ts +1 -2
  36. package/dist/registry.d.ts +1412 -203
  37. package/dist/registry.js +30 -3
  38. package/dist/schemas/index.d.ts +1 -1
  39. package/dist/schemas/index.js +3 -2
  40. package/dist/storyAdapter.d.ts +1 -2
  41. package/dist/storyAdapter.js +11 -49
  42. package/dist/storyAdapter.js.map +1 -1
  43. package/dist/test-utils.d.ts +3 -2
  44. package/dist/topology/index.d.ts +1 -1
  45. package/dist/topology/index.js +1 -1
  46. package/package.json +8 -2
  47. package/src/__tests__/contract-parser.test.ts +318 -277
  48. package/src/__tests__/preview-runtime-hook.test.tsx +315 -0
  49. package/src/__tests__/preview-runtime.test.tsx +30 -8
  50. package/src/__tests__/schema.test.ts +191 -14
  51. package/src/analysis-plan/analysis-plan-v1.test.ts +320 -0
  52. package/src/analysis-plan/coverage.ts +181 -0
  53. package/src/analysis-plan/digest.ts +141 -0
  54. package/src/analysis-plan/index.ts +34 -0
  55. package/src/analysis-plan/types.ts +207 -0
  56. package/src/approved-contract-tokens.test.ts +39 -0
  57. package/src/approved-contract-tokens.ts +18 -0
  58. package/src/codes/__tests__/codes.test.ts +13 -0
  59. package/src/codes/codes.ts +40 -0
  60. package/src/compiled-types/index.ts +640 -39
  61. package/src/compiled-types/parse.test.ts +145 -4
  62. package/src/component-contract.ts +95 -53
  63. package/src/composition.ts +7 -13
  64. package/src/constants.ts +3 -6
  65. package/src/contract/hash.test.ts +20 -0
  66. package/src/contract/hash.ts +66 -9
  67. package/src/contract/index.ts +24 -1
  68. package/src/contract/manifest.test.ts +94 -0
  69. package/src/contract/manifest.ts +68 -0
  70. package/src/contract/preimage.test.ts +219 -1
  71. package/src/contract/preimage.ts +326 -6
  72. package/src/contract/stamp.test.ts +3 -0
  73. package/src/contract/stamp.ts +1 -1
  74. package/src/contract-parser.ts +54 -30
  75. package/src/defineFragment.test.ts +476 -91
  76. package/src/defineFragment.ts +204 -114
  77. package/src/domain-ids.test.ts +35 -0
  78. package/src/domain-ids.ts +61 -0
  79. package/src/evaluation/evaluate.test.ts +522 -0
  80. package/src/evaluation/evaluate.ts +690 -0
  81. package/src/evaluation/evaluation-v2-receipt-v1.test.ts +772 -0
  82. package/src/evaluation/index.ts +58 -0
  83. package/src/evaluation/receipt.ts +753 -0
  84. package/src/evaluation/types.ts +406 -0
  85. package/src/facts/builders.ts +2 -0
  86. package/src/facts/compile.ts +29 -6
  87. package/src/facts/fact-index.ts +13 -3
  88. package/src/facts/fact-integrity-v1.test.ts +172 -0
  89. package/src/facts/facts.test.ts +15 -0
  90. package/src/facts/ids.ts +46 -3
  91. package/src/facts/index.ts +14 -1
  92. package/src/facts/integrity.ts +134 -0
  93. package/src/facts/types.ts +36 -0
  94. package/src/governance-integrity.test.ts +1 -0
  95. package/src/governance-integrity.ts +5 -3
  96. package/src/governance-telemetry.ts +8 -0
  97. package/src/governance.ts +70 -8
  98. package/src/index.ts +230 -37
  99. package/src/preview/validation.test.ts +62 -0
  100. package/src/preview/validation.ts +48 -2
  101. package/src/preview-runtime.tsx +227 -20
  102. package/src/registry-install-plan.ts +200 -109
  103. package/src/registry-shards.test.ts +263 -0
  104. package/src/registry.ts +237 -0
  105. package/src/repository-binding.test.ts +50 -0
  106. package/src/repository-binding.ts +96 -0
  107. package/src/rules/families.test.ts +36 -0
  108. package/src/rules/finding.ts +7 -2
  109. package/src/rules/index.ts +17 -1
  110. package/src/rules/rule-config.test.ts +66 -0
  111. package/src/rules/rule-config.ts +73 -0
  112. package/src/rules/rules.test.ts +26 -0
  113. package/src/rules/tokens-css-vars-must-be-defined.test.ts +51 -2
  114. package/src/rules/tokens-css-vars-must-be-defined.ts +34 -1
  115. package/src/schema.ts +293 -113
  116. package/src/schemas/index.ts +1 -1
  117. package/src/storyAdapter.test.ts +68 -12
  118. package/src/storyAdapter.ts +44 -75
  119. package/src/topology/resolve-area.ts +1 -1
  120. package/src/types.ts +258 -40
  121. package/dist/chunk-3LLRNCPX.js.map +0 -1
  122. package/dist/chunk-RANPUC6C.js +0 -72
  123. package/dist/chunk-RANPUC6C.js.map +0 -1
  124. package/dist/chunk-XN3LSDPY.js.map +0 -1
  125. package/dist/chunk-YF65VYRY.js.map +0 -1
  126. package/src/fragment-types.ts +0 -214
  127. package/src/react-create-element.test.ts +0 -22
  128. package/src/react-create-element.ts +0 -12
  129. package/src/storyFilters.test.ts +0 -350
  130. package/src/storyFilters.ts +0 -253
@@ -1,253 +0,0 @@
1
- /**
2
- * Smart filtering for Storybook adapter.
3
- *
4
- * Two layers:
5
- * 1. Per-file heuristics — checkStoryExclusion() checks title, tags, component name, etc.
6
- * 2. Cross-file sub-component detection — detectSubComponentPaths() uses directory structure.
7
- *
8
- * All functions are pure (no I/O, no side effects) for easy testing.
9
- */
10
-
11
- import type { StorybookFilterConfig } from './types.js';
12
-
13
- // ---------------------------------------------------------------------------
14
- // Types
15
- // ---------------------------------------------------------------------------
16
-
17
- export type ExclusionReason =
18
- | 'deprecated' // title contains "Deprecated"
19
- | 'test-story' // title ends /tests? OR file matches *.test.stories.*
20
- | 'svg-icon' // component name starts with Svg[A-Z]
21
- | 'tag-excluded' // meta.tags includes hidden/internal/no-fragment
22
- | 'empty-variants' // zero renderable story exports
23
- | 'sub-component' // directory-based: file in another component's folder
24
- | 'config-excluded'; // user explicit exclude pattern
25
-
26
- export interface ExclusionResult {
27
- excluded: boolean;
28
- reason?: ExclusionReason;
29
- detail?: string;
30
- }
31
-
32
- // ---------------------------------------------------------------------------
33
- // Per-file heuristics
34
- // ---------------------------------------------------------------------------
35
-
36
- const EXCLUDED_TAGS = new Set(['hidden', 'internal', 'no-fragment']);
37
-
38
- const SVG_ICON_RE = /^Svg[A-Z]/;
39
- const TEST_TITLE_RE = /\/tests?$/i;
40
- const TEST_FILE_RE = /\.test\.stories\./;
41
- const DEPRECATED_TITLE_RE = /\bDeprecated\b/i;
42
-
43
- export interface CheckStoryExclusionOpts {
44
- storybookTitle?: string;
45
- componentName: string;
46
- componentDisplayName?: string;
47
- componentFunctionName?: string;
48
- tags?: string[];
49
- variantCount: number;
50
- filePath: string;
51
- config: StorybookFilterConfig;
52
- }
53
-
54
- /**
55
- * Per-file exclusion check. Returns `{ excluded: true, reason, detail }` when
56
- * the fragment should be filtered out, or `{ excluded: false }` when it should
57
- * be kept.
58
- *
59
- * Config `include` trumps everything — if a name matches `include`, it is
60
- * never excluded by heuristics.
61
- */
62
- export function checkStoryExclusion(opts: CheckStoryExclusionOpts): ExclusionResult {
63
- const { config } = opts;
64
-
65
- // Force-included names bypass all heuristic filters
66
- if (isForceIncluded(opts.componentName, config)) {
67
- return { excluded: false };
68
- }
69
-
70
- // Config explicit exclude
71
- if (isConfigExcluded(opts.componentName, config)) {
72
- return {
73
- excluded: true,
74
- reason: 'config-excluded',
75
- detail: `'${opts.componentName}' matches storybook.exclude pattern`,
76
- };
77
- }
78
-
79
- // Deprecated
80
- if (config.excludeDeprecated !== false && opts.storybookTitle && DEPRECATED_TITLE_RE.test(opts.storybookTitle)) {
81
- return {
82
- excluded: true,
83
- reason: 'deprecated',
84
- detail: `Title "${opts.storybookTitle}" contains "Deprecated"`,
85
- };
86
- }
87
-
88
- // Test stories
89
- if (config.excludeTests !== false) {
90
- if (opts.storybookTitle && TEST_TITLE_RE.test(opts.storybookTitle)) {
91
- return {
92
- excluded: true,
93
- reason: 'test-story',
94
- detail: `Title "${opts.storybookTitle}" ends with /test(s)`,
95
- };
96
- }
97
- if (TEST_FILE_RE.test(opts.filePath)) {
98
- return {
99
- excluded: true,
100
- reason: 'test-story',
101
- detail: `File path matches *.test.stories.*`,
102
- };
103
- }
104
- }
105
-
106
- // SVG icons
107
- if (config.excludeSvgIcons !== false) {
108
- const names = [opts.componentName, opts.componentDisplayName, opts.componentFunctionName].filter(Boolean) as string[];
109
- for (const name of names) {
110
- if (SVG_ICON_RE.test(name)) {
111
- return {
112
- excluded: true,
113
- reason: 'svg-icon',
114
- detail: `Component name "${name}" matches Svg[A-Z] pattern`,
115
- };
116
- }
117
- }
118
- }
119
-
120
- // Excluded tags
121
- if (opts.tags?.length) {
122
- const hit = opts.tags.find(t => EXCLUDED_TAGS.has(t));
123
- if (hit) {
124
- return {
125
- excluded: true,
126
- reason: 'tag-excluded',
127
- detail: `Tag "${hit}" is in the exclusion set`,
128
- };
129
- }
130
- }
131
-
132
- // Empty variants
133
- if (opts.variantCount === 0) {
134
- return {
135
- excluded: true,
136
- reason: 'empty-variants',
137
- detail: 'Zero renderable story exports',
138
- };
139
- }
140
-
141
- return { excluded: false };
142
- }
143
-
144
- // ---------------------------------------------------------------------------
145
- // Cross-file sub-component detection
146
- // ---------------------------------------------------------------------------
147
-
148
- /**
149
- * Given all story file relative paths, detect which ones are sub-components
150
- * based on directory structure.
151
- *
152
- * Heuristic: within a directory, if one story file's base name matches the
153
- * directory name, it is the "primary" component. All other story files in
154
- * the same directory are considered sub-components.
155
- *
156
- * Example:
157
- * src/components/Form/Form.stories.tsx → primary ("Form")
158
- * src/components/Form/Checkbox.stories.tsx → sub-component of "Form"
159
- * src/components/Form/RadioGroup.stories.tsx → sub-component of "Form"
160
- *
161
- * Returns a Map from relative path → parent component name.
162
- * Paths NOT in the map are standalone components.
163
- */
164
- export function detectSubComponentPaths(
165
- storyFiles: Array<{ relativePath: string }>
166
- ): Map<string, string> {
167
- // Group story files by their parent directory
168
- const byDir = new Map<string, Array<{ relativePath: string; baseName: string }>>();
169
-
170
- for (const file of storyFiles) {
171
- const parts = file.relativePath.split('/');
172
- if (parts.length < 2) continue; // skip root-level files
173
-
174
- const fileName = parts[parts.length - 1];
175
- // Extract base name: "Form.stories.tsx" → "Form"
176
- const baseMatch = fileName.match(/^([^.]+)\.stories\./);
177
- if (!baseMatch) continue;
178
-
179
- const dir = parts.slice(0, -1).join('/');
180
- const baseName = baseMatch[1];
181
-
182
- if (!byDir.has(dir)) byDir.set(dir, []);
183
- byDir.get(dir)!.push({ relativePath: file.relativePath, baseName });
184
- }
185
-
186
- const subComponentMap = new Map<string, string>();
187
-
188
- for (const [dir, files] of byDir) {
189
- if (files.length <= 1) continue; // single file in dir → always standalone
190
-
191
- // Directory name is the last segment: "src/components/Form" → "Form"
192
- const dirName = dir.split('/').pop()!;
193
-
194
- // Find the primary: story whose base name matches the directory name
195
- const primary = files.find(f => f.baseName === dirName);
196
- if (!primary) continue; // no clear primary → keep all
197
-
198
- // All others in this dir are sub-components
199
- for (const file of files) {
200
- if (file.relativePath === primary.relativePath) continue;
201
- subComponentMap.set(file.relativePath, primary.baseName);
202
- }
203
- }
204
-
205
- return subComponentMap;
206
- }
207
-
208
- // ---------------------------------------------------------------------------
209
- // Config helpers
210
- // ---------------------------------------------------------------------------
211
-
212
- /**
213
- * Check if a component name matches the `storybook.include` patterns.
214
- * Include is a force-include that bypasses all heuristic filters.
215
- */
216
- export function isForceIncluded(name: string, config: StorybookFilterConfig): boolean {
217
- if (!config.include?.length) return false;
218
- return config.include.some(pattern => matchesPattern(name, pattern));
219
- }
220
-
221
- /**
222
- * Check if a component name matches the `storybook.exclude` patterns.
223
- */
224
- export function isConfigExcluded(name: string, config: StorybookFilterConfig): boolean {
225
- if (!config.exclude?.length) return false;
226
- return config.exclude.some(pattern => matchesPattern(name, pattern));
227
- }
228
-
229
- /**
230
- * Simple pattern matching: exact match or glob-style prefix/suffix wildcards.
231
- * "Button" → exact match
232
- * "Svg*" → prefix match
233
- * "*Icon" → suffix match
234
- * "*Badge*" → contains match
235
- */
236
- function matchesPattern(name: string, pattern: string): boolean {
237
- if (!pattern.includes('*')) {
238
- return name === pattern;
239
- }
240
-
241
- const parts = pattern.split('*');
242
- if (parts.length === 2) {
243
- const [prefix, suffix] = parts;
244
- if (prefix && suffix) return name.startsWith(prefix) && name.endsWith(suffix);
245
- if (prefix) return name.startsWith(prefix);
246
- if (suffix) return name.endsWith(suffix);
247
- return true; // pattern is just "*"
248
- }
249
-
250
- // Multi-wildcard: convert to regex
251
- const escaped = parts.map(p => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('.*');
252
- return new RegExp(`^${escaped}$`).test(name);
253
- }