@designtools/manifest 0.0.0-stage → 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # @designtools/manifest
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3da728f: From the first end-to-end run:
8
+
9
+ - A comment after a declaration on the same line (`--size-xl: 3rem; /* 48px controls */`) now describes that declaration. It used to become the next token's description, so every description in a scale written that way landed one token late.
10
+ - A token re-declared in a later stylesheet records it in `overriddenIn`.
11
+ - Each component records `import`, the specifier an app imports it by through the tsconfig path alias that reaches the system folder (`@ds/button/button`), so the import line in the docs and the agent markdown resolves.
12
+ - Brand assets keep the order `assets.json` gives them, so the default logo leads.
13
+ - `prose-check` reads the places listed in `manifest.prose` (a folder contributes its markdown and `*content.ts(x)` files), treats a TypeScript template literal as prose rather than code, and honours `prose-check-ignore`, `prose-check-ignore-next-line` and `prose-check-ignore-start` … `-end` for pages that name wrong forms on purpose.
14
+ - A prop's JSDoc no longer leaks into other components. react-docgen-typescript caches a prop by the file of its first declaration, so Alert's documented `children` (first declared by React) gave its description, type and declarations to every component with `children`. Each component now reads its props afresh.
15
+ - `agents` writes to `AGENTS.md` when `CLAUDE.md` imports it (`@AGENTS.md`, as `next dev` writes it), so every agent reads the section; `manifest.agents` in `designtools.json` names another file. The section no longer forbids every ramp step: ramps are for charts, illustration and a decorative colour, never text, surfaces or actions.
16
+ - `manifest.usage` names the file `@designtools/tokens --usage` writes; every colour that fails somewhere as text or a shape becomes a rule in rules.json (`usage-<colour>`), marked with the new status `measured`: a fact from the tokens, not a client decision. Status fills are left to the default status-text rule.
17
+
18
+ ## 0.1.0
19
+
20
+ ### Minor Changes
21
+
22
+ - First release. `designtools-manifest build` reads a React design system, and the brand around it, into committed JSON inside the system folder:
23
+ - `components.json`: props through react-docgen-typescript; variants from `tv()` or `cva()` configs, local or imported, or the props' literal unions when there is neither; `data-slot` parts; status and usage from JSDoc (`@status`, `@use`, `@avoid`, `@instead`, `@replaces`, `@role`, `@keyboard`); and `*.examples.tsx`: canonical, do and don't, each with its JSX.
24
+ - `tokens.json`: every custom property in the token stylesheets, with its light, dark and P3 values and the comment above it.
25
+ - `rules.json`, `patterns.json`, `taxonomy.json` and `assets.json`: rules from `*.rule.json` (with a JSON Schema), patterns from `*.pattern.tsx`, the system's names with their curated wrong forms, and the brand assets with how to use them.
26
+
27
+ `check` fails when the committed files are out of date. `diff <base>` classifies every change as breaking, additive, visual or docs. `agents` writes the pointer section of CLAUDE.md or AGENTS.md, `prose-check` warns about wrong and restated names without ever failing, and `provenance` prints the version and commit for generated pages.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Made by Many Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,175 @@
1
- # Temporary Holding Version
1
+ # @designtools/manifest
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Reads a React design system, and the brand around it, into committed JSON: every component with its props, variants, parts, usage, status and examples; every token; the rules, brand and interface alike; the product's patterns; one vocabulary with its wrong forms; and the brand assets. Docs pages, checks and agents read those files instead of the source, so none of them has to parse TypeScript, and none of them drifts from it.
4
+
5
+ ```bash
6
+ npx @designtools/manifest build # writes src/ds/manifest/*.json
7
+ npx @designtools/manifest check # exits 1 if the committed files are out of date
8
+ npx @designtools/manifest diff main # classifies every change against main
9
+ npx @designtools/manifest agents # writes the pointer section of CLAUDE.md or AGENTS.md
10
+ npx @designtools/manifest prose-check # warns about wrong and restated names in prose; never fails
11
+ npx @designtools/manifest provenance # "Generated from acme-web@1.4.0 at 3f2a9c1", for generated pages
12
+ ```
13
+
14
+ Deterministic: the same source gives the same bytes, with sorted keys, no timestamps and no absolute paths, so a diff of the files shows only real changes.
15
+
16
+ ## Setup
17
+
18
+ Record the system folder and the token stylesheets once, in `designtools.json` at the project root:
19
+
20
+ ```json
21
+ {
22
+ "manifest": {
23
+ "system": "src/ds",
24
+ "tokens": ["app/styles/tokens.css", "app/styles/scale.css"]
25
+ }
26
+ }
27
+ ```
28
+
29
+ The manifest is written inside the system folder (`src/ds/manifest/`), so it moves with the system if the system moves to its own package. Flags override the file: `--system`, `--tokens` (repeat it), `--tsconfig`, `--out`, `--root`.
30
+
31
+ List every stylesheet that declares a token, in the order the app imports them: the generated colour tiers, the authored scale, and wherever the font families live (`base.css` on the suite's default stack). A token re-declared in a later file takes that file's value and records it in `overriddenIn`. `prose` adds places for `prose-check` to read (see [For agents](#for-agents)).
32
+
33
+ ## What it reads
34
+
35
+ **Components.** Every exported component in a `.tsx` file under the system folder. Fixtures, tests, stories and `.d.ts` files are skipped. Props come from [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript), run once over a single TypeScript program, so types resolve across files and through the project's path aliases. A component's own props are kept, and so are those of a Base UI primitive it wraps. Props inherited from the DOM, ARIA or React are left out, and recorded as what it `inherits` (`"span"`, `"@base-ui/react/select:Select.Root"`).
36
+
37
+ **Variants.** Read from the `tv()` (tailwind-variants) or `cva()` call, not inferred from types, because the config is already data: axes, options, defaults, compound conditions, and a `tv()` config's named parts. The config can be in the component's file or imported from another project file. A component with no config falls back to its own props whose types are unions of string literals.
38
+
39
+ **Slots.** Every literal `data-slot` the component renders, including those rendered by private helpers in the same file.
40
+
41
+ **Examples.** A co-located `<name>.examples.tsx`. `canonical` is the one to copy; `do…` and `dont…` exports pair up in order; anything else is a further example. Each records its JSDoc (the why) and the JSX it returns, as written, so docs can show the code and agents can copy it. The manifest never runs them. There is no register of states: loading, empty and error stay with each screen.
42
+
43
+ **JSDoc.** Optional, and nothing is required. A component's JSDoc, or failing that its variant config's, is its description. These tags are read:
44
+
45
+ | Tag | Becomes |
46
+ | --- | --- |
47
+ | `@name` | The display name, when it should differ from the export |
48
+ | `@description` | Added to the description |
49
+ | `@category` | The docs navigation group |
50
+ | `@example` | A JSX snippet; repeat for several |
51
+ | `@see` | A link or a related component; repeat for several |
52
+ | `@deprecated` | The component, or a prop, is deprecated, with the reason |
53
+ | `@primitive` | The primitive it wraps |
54
+ | `@aria` | The ARIA pattern it follows |
55
+ | `@status` | `stable`, `emerging` or `deprecated`, then an optional note |
56
+ | `@use` | When to reach for it |
57
+ | `@avoid` | When not to |
58
+ | `@instead` | What to use instead, comma-separated |
59
+ | `@replaces` | Raw elements it stands in for (`button`), which the adherence report counts |
60
+ | `@role`, `@keyboard` | What assistive technology meets, and the keys it answers |
61
+ | `@nodocgen` | Leaves the component out |
62
+
63
+ Any other tag is a warning, with a suggestion when it is close to one of these.
64
+
65
+ **Tokens.** Every custom property in the listed stylesheets: the colour tiers `@designtools/tokens` generates and the scale you author beside them. Each token records its value in every context it is declared in: `default` (`@theme`, `:root`), `light`, `dark`, `p3:` for the wide-gamut layer, and any other selector as written. A `prefers-color-scheme` fallback never overrides an explicit dark block. The comment above a declaration, or above the run of declarations it starts, becomes its description; a comment after a declaration on the same line describes that declaration alone. Tiers follow Tailwind's namespaces (`--text-*`, `--radius-*`, …); semantic colours like `--primary` are recognised by their values.
66
+
67
+ **Rules.** One `<id>.rule.json` per rule in `<system>/rules`, brand and interface in the same format: title, statement, rationale, threshold, what it applies to, exceptions, the tokens it rests on, whether it is `confirmed` or still an `assumption`, and the check that proves it. [`schemas/rule.schema.json`](schemas/rule.schema.json) validates them in an editor.
68
+
69
+ **Patterns.** Any `<id>.pattern.tsx` in the system folder. The file's JSDoc names and describes it (`@name`, `@status`), its imports say which components it composes, and each named export is a composition, recorded like an example.
70
+
71
+ **Taxonomy.** The canonical names come from everything else: components, variant axes and their meaningful options, semantic colours, patterns and rules. `<system>/taxonomy.json` adds the wrong forms (`{ "name": "destructive", "wrong": ["error", "danger"] }`) and product terms the code never names (`{ "name": "sign in", "kind": "product", "wrong": ["log in"] }`).
72
+
73
+ **Measured usage rules.** With `manifest.usage` naming the file `@designtools/tokens --usage` writes, every colour that fails somewhere, as text (4.5:1 at AA) or as a shape (3:1), gets a rule in rules.json: `usage-primary`, "`--primary` reads as text on … On … it is neither, down to 1.06:1 …". They are marked `measured`, a fact from the tokens that changes when they do, and sit beside the authored rules on the rules page. A brand colour's limits are then a brand decision, written as a confirmed brand rule.
74
+
75
+ **Brand assets.** Every image in `<system>/brand`, with an `assets.json` there saying how to use each: kind, usage, minimum size, clear space, the surfaces it may sit on, alt text. SVG and PNG sizes are read from the files. They keep the order `assets.json` gives them, so the default logo can lead. A file the index does not mention is listed anyway, after them, with a warning.
76
+
77
+ ## The files
78
+
79
+ `components.json`, abridged:
80
+
81
+ ```json
82
+ {
83
+ "generator": "@designtools/manifest@0.1.0",
84
+ "schema": "designtools.manifest/1",
85
+ "system": "src/ds",
86
+ "components": [
87
+ {
88
+ "name": "Badge",
89
+ "export": "Badge",
90
+ "source": "src/ds/badge/badge.tsx",
91
+ "import": "@ds/badge/badge",
92
+ "description": "A pill: soft tinted background, strong text of the same hue.",
93
+ "inherits": ["span"],
94
+ "props": {
95
+ "intent": { "type": "\"default\" | \"neutral\" | \"success\"", "values": ["default", "neutral", "success"], "required": false }
96
+ },
97
+ "variants": {
98
+ "from": "tv",
99
+ "config": "badge",
100
+ "axes": [{ "name": "intent", "default": "neutral", "options": [{ "name": "default" }, { "name": "neutral" }, { "name": "success" }] }]
101
+ },
102
+ "slots": ["badge"],
103
+ "status": "stable",
104
+ "usage": { "use": "A short status beside the thing it describes.", "avoid": "Anything people can press.", "instead": ["Button"] },
105
+ "examples": {
106
+ "source": "src/ds/badge/badge.examples.tsx",
107
+ "canonical": { "name": "canonical", "code": "<Badge intent=\"success\">Paid</Badge>" },
108
+ "do": [{ "name": "doShortLabel", "description": "One or two words, in sentence case." }],
109
+ "dont": [{ "name": "dontClickable", "description": "A badge is not a button." }],
110
+ "other": []
111
+ }
112
+ }
113
+ ]
114
+ }
115
+ ```
116
+
117
+ `tokens.json`, abridged:
118
+
119
+ ```json
120
+ {
121
+ "generator": "@designtools/manifest@0.1.0",
122
+ "schema": "designtools.manifest/1",
123
+ "sources": ["app/styles/tokens.css", "app/styles/scale.css"],
124
+ "tokens": [
125
+ { "name": "--primary", "tier": "color", "values": { "light": "var(--color-primary-700)", "dark": "var(--color-primary-800)" }, "source": "app/styles/tokens.css" },
126
+ { "name": "--radius-md", "tier": "radius", "values": { "default": "0.375rem" }, "description": "corners, scaled to the element", "source": "app/styles/scale.css" }
127
+ ]
128
+ }
129
+ ```
130
+
131
+ Beside them sit `rules.json`, `patterns.json`, `taxonomy.json` and `assets.json`, under the same rules. The full schema is in [`src/types.ts`](src/types.ts), which has no imports so it can be copied: `@designtools/blocks` carries an identical copy.
132
+
133
+ ## Commands
134
+
135
+ | Command | Exit code |
136
+ | --- | --- |
137
+ | `build` | 0, or 2 on a usage error |
138
+ | `check` | 0 when both files match the source, 1 when either is missing or out of date. A version change is reported as such |
139
+ | `diff [base]` | 0, or 1 with `--fail-on <class>` when a change of that class is found. `base` defaults to `main` |
140
+ | `agents` | 0; with `--check`, 1 when the section is out of date |
141
+ | `prose-check [file…]` | Always 0. Prose is for people to fix, never a reason to fail a build |
142
+ | `provenance` | 0 |
143
+
144
+ `diff` builds the manifest from the current source and compares it with the files committed at `base`. Every change is classified:
145
+
146
+ | Class | Examples |
147
+ | --- | --- |
148
+ | breaking | A component, prop, variant option, token or `data-slot` removed; a prop made required; a new required prop; a prop type changed |
149
+ | additive | A new component, optional prop, variant option, token, slot or state |
150
+ | visual | A token value or a default variant changed |
151
+ | docs | A description, status, usage, example, rule, pattern, term or asset changed |
152
+
153
+ Components are matched by their path inside the system folder, so moving the whole system is not a change. The report is markdown, ready to post on a pull request; `--json` prints the changes as data.
154
+
155
+ ## For agents
156
+
157
+ `agents` writes a section of `CLAUDE.md` or `AGENTS.md` between markers, and leaves the rest of the file alone. It picks `AGENTS.md` when `CLAUDE.md` imports it (`@AGENTS.md`, as `next dev` writes it), so every agent reads the section and Claude reaches it through the import; otherwise `CLAUDE.md` if there is one. `manifest.agents` in `designtools.json`, or `--file`, names another. It points agents at each manifest file and the docs, and lists nothing: a list of components or tokens written into prose is a second copy that drifts.
158
+
159
+ `prose-check` reads `CLAUDE.md`, `AGENTS.md`, `.claude/`, `docs/` and the system folder's markdown, plus anything listed in `manifest.prose` (a folder there contributes its markdown and its `*content.ts(x)` files, which is where a docs site keeps its editorial copy), and warns about a component tag the system does not have (`<Modal>`), a wrong form from the taxonomy (`Dropdown` for `Select`, "log in" for "sign in"), and a paragraph or list that restates several components or tokens. The generated section is skipped. In TypeScript a backtick opens a template literal, so its words are read as prose, not code. A page that names wrong forms on purpose, such as a voice page saying "never the customer", marks them: `prose-check-ignore` on a line skips it, `prose-check-ignore-next-line` skips the next, and `prose-check-ignore-start` … `prose-check-ignore-end` skip a block, in any comment syntax.
160
+
161
+ `provenance` prints the project's version and the commit it was built at (`VERCEL_GIT_COMMIT_SHA` or `GITHUB_SHA` when set, else git), for the header of a generated docs page. A generated page never carries a review date.
162
+
163
+ ## Programmatic use
164
+
165
+ ```ts
166
+ import { buildManifest, diffManifests, loadConfig } from "@designtools/manifest";
167
+
168
+ const built = buildManifest(loadConfig({ root: "." }));
169
+ built.components.components; // ComponentEntry[]
170
+ built.files; // { "src/ds/manifest/components.json": "…" }
171
+ ```
172
+
173
+ ## Licence
174
+
175
+ [MIT](LICENSE), © Made by Many Ltd.