Skip to content

Commit 2f3aa99

Browse files
committed
AI: update ai context files for build/specs
1 parent db70525 commit 2f3aa99

File tree

4 files changed

+622
-323
lines changed

4 files changed

+622
-323
lines changed

ai/guides/development/build-system.md

Lines changed: 41 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,9 @@ import styles from './css/button-bundle.css'; // No @imports!
325325

326326
#### B. Spec System (JS Source → JSON Snapshot + Component Spec)
327327

328-
**The New Architecture** (as of 2025-01):
328+
Component specs are authored in **JavaScript** (`.spec.js` files) with JSON snapshots generated for tooling.
329329

330-
Component specs are now authored in **JavaScript** (`.spec.js` files) with JSON snapshots generated for tooling.
330+
> **Historical Note**: Prior to November 2025, specs were authored as `.json` files with `.js` files generated from them. This was reversed to provide better DX (comments, imports, trailing commas). If you encounter guides or documentation referencing editing `.json` spec files, that is legacy information - all specs should now be authored as `.spec.js` files.
331331
332332
**Source spec format** (`.spec.js`):
333333
```javascript
@@ -400,61 +400,29 @@ Ensures specs remain JSON-serializable:
400400
};
401401
```
402402

403-
#### C. Legacy JSON Support (Transitional)
403+
#### C. Spec Processing Flow
404404

405-
**Dual format support** during migration:
406405
```javascript
407-
// Supports both:
408-
const jsonFiles = await glob('src/primitives/**/specs/*.json');
406+
// Get all .spec.js source files
409407
const specJsFiles = await glob('src/primitives/**/specs/*.spec.js');
408+
const entryPoints = specJsFiles;
410409

411-
const allFiles = [...jsonFiles, ...specJsFiles];
412-
```
413-
414-
**Legacy `.json` files**:
415-
- Still supported (read directly)
416-
- Generate `.component.js` output
417-
- Will be migrated to `.spec.js` over time
418-
419-
**Exclusions** (generated files not processed):
420-
```javascript
421-
const entryPoints = allFiles.filter(path =>
422-
!path.endsWith('.component.json') // Generated
423-
&& !path.endsWith('.component.js') // Generated
424-
&& !path.endsWith('.spec.json') // Generated from .spec.js
425-
);
426-
```
427-
428-
#### D. Spec Processing Flow
429-
430-
```javascript
431410
const createComponentSpecs = async () => {
432411
await asyncEach(entryPoints, async (entryPath) => {
433-
let spec;
434-
const isJsSpec = entryPath.endsWith('.spec.js');
412+
// Load JS module with cache busting for watch mode
413+
const specModule = await import(`${pathToFileURL(entryPath).href}?t=${Date.now()}`);
414+
const spec = specModule.default;
435415

436-
if (isJsSpec) {
437-
// Load JS module with cache busting for watch mode
438-
const specModule = await import(`${pathToFileURL(entryPath).href}?t=${Date.now()}`);
439-
spec = specModule.default;
416+
// Validate purity
417+
validateSpec(spec, entryPath);
440418

441-
// Validate purity
442-
validateSpec(spec, entryPath);
419+
// Generate JSON snapshot
420+
const jsonPath = entryPath.replace('.spec.js', '.spec.json');
421+
writeFileSync(jsonPath, JSON.stringify(spec, null, 2));
443422

444-
// Generate JSON snapshot
445-
const jsonPath = entryPath.replace('.spec.js', '.spec.json');
446-
writeFileSync(jsonPath, JSON.stringify(spec, null, 2));
447-
}
448-
else {
449-
// Legacy JSON loading
450-
spec = JSON.parse(readFileSync(entryPath, 'utf8'));
451-
}
452-
453-
// Generate component spec (both paths converge here)
423+
// Generate component spec
454424
const componentSpecJS = await generateComponentSpecJS(spec, false, {}, entryPath);
455-
const componentJSPath = isJsSpec
456-
? entryPath.replace('.spec.js', '.component.js')
457-
: entryPath.replace('.json', '.component.js');
425+
const componentJSPath = entryPath.replace('.spec.js', '.component.js');
458426
writeFileSync(componentJSPath, componentSpecJS);
459427

460428
// Generate plural variant if supported
@@ -474,45 +442,31 @@ Source: Generated:
474442
button.spec.jsbutton.spec.json (snapshot)
475443
(authored) → button.component.js (processed)
476444
buttons.component.js (if plural)
477-
478-
OR (legacy):
479-
480-
button.jsonbutton.component.js (processed)
481-
(authored) → buttons.component.js (if plural)
482445
```
483446
484-
#### E. Watch Mode for Specs
447+
#### D. Watch Mode for Specs
485448
486449
```javascript
487450
if (watch) {
488-
// Watch both legacy JSON and source .spec.js files
489-
const jsonSpecFiles = await glob('src/primitives/**/specs/*.json');
490-
const jsSpecFiles = await glob('src/primitives/**/specs/*.spec.js');
491-
492-
// Exclude generated files
493-
const watchedFiles = [...jsonSpecFiles, ...jsSpecFiles].filter(
494-
path =>
495-
!path.endsWith('.component.json')
496-
&& !path.endsWith('.component.js')
497-
&& !path.endsWith('.spec.json'), // Don't watch generated JSON
498-
);
499-
500-
specWatcher = build({
501-
watch,
502-
write: false, // Don't write esbuild output
503-
logLevel: 'silent', // Just watch for changes
504-
entryPoints: watchedFiles,
505-
plugins: [
506-
callbackPlugin({
507-
onComplete: async (result, { isRebuild }) => {
508-
if (isRebuild) {
509-
await createComponentSpecs();
510-
await generateJSExportsFromSpecs();
511-
}
512-
},
513-
}),
514-
],
515-
});
451+
// Watch .spec.js source files
452+
if (entryPoints.length > 0) {
453+
specWatcher = build({
454+
watch,
455+
write: false, // Don't write esbuild output
456+
logLevel: 'silent', // Just watch for changes
457+
entryPoints, // Same entryPoints (*.spec.js files)
458+
outdir: '.temp-watch', // Required by esbuild
459+
plugins: [
460+
callbackPlugin({
461+
onComplete: async (result, { isRebuild }) => {
462+
if (isRebuild) {
463+
await createComponentSpecs();
464+
}
465+
},
466+
}),
467+
],
468+
});
469+
}
516470
}
517471
```
518472
@@ -1394,10 +1348,12 @@ watch({
13941348
13951349
### 2. JS → JSON Snapshot Generation (Spec System)
13961350
1351+
> **Historical Note**: This architecture was reversed in November 2025. Previously, JSON was the source with JS generated. Now JS is the source with JSON generated as snapshots.
1352+
13971353
**Why it happens**:
1398-
- **JS is the source of truth** for component specs (as of 2025-01)
1354+
- **JS is the source of truth** for component specs
13991355
- Allows comments, imports, trailing commas, better DX
1400-
- But tooling/LLMs benefit from JSON snapshots
1356+
- Tooling/LLMs benefit from JSON snapshots for machine readability
14011357
14021358
**Solution**:
14031359
- Author specs in `.spec.js` format:
@@ -1427,8 +1383,8 @@ watch({
14271383
14281384
**Impact**:
14291385
- `.spec.js` files authored by developers
1430-
- `.spec.json` files generated by build
1431-
- `.component.js` files generated from either source
1386+
- `.spec.json` files generated by build (snapshot)
1387+
- `.component.js` files generated from spec (processed)
14321388
- All committed to repo for source consumption
14331389
14341390
---
@@ -1475,7 +1431,6 @@ buttons.component.js # Generated component spec (plural, if supported)
14751431
- Multiple generated files per spec
14761432
- Spec changes require rebuild
14771433
- Watch mode handles auto-regeneration with cache busting
1478-
- Legacy `.json` specs still supported during transition
14791434
14801435
---
14811436
@@ -1682,7 +1637,6 @@ What do you need to build?
16821637
| Source specs (JS) | `src/primitives/*/specs/*.spec.js` |
16831638
| Generated specs (JSON) | `src/primitives/*/specs/*.spec.json` |
16841639
| Generated component specs | `src/primitives/*/specs/*.component.js` |
1685-
| Legacy specs (JSON) | `src/primitives/*/specs/*.json` (transitional) |
16861640
| Package source | `packages/*/src/` |
16871641
| Package dist | `packages/*/dist/` |
16881642
| Core source | `src/` |
@@ -1700,7 +1654,6 @@ What do you need to build?
17001654
| `*.spec.json` | Generated | JSON snapshot for tooling/LLMs | ✅ Yes |
17011655
| `*.component.js` | Generated | Processed component spec (singular) | ✅ Yes |
17021656
| `*s.component.js` | Generated | Plural variant (e.g., `buttons.component.js`) | ✅ Yes |
1703-
| `*.json` | Legacy | Old JSON specs (transitional) | ✅ Yes |
17041657
17051658
**Example for button primitive**:
17061659
```

0 commit comments

Comments
 (0)