@reforma/project-tokens 0.0.1 → 0.0.2

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/README.md CHANGED
@@ -1,12 +1,52 @@
1
1
  # @reforma/project-tokens
2
2
 
3
3
  Compile project DTCG JSON into CSS, Tailwind theme bindings, and mode metadata.
4
- The compiler runs locally on Node 24 or newer. It does not call a Reforma service.
4
+ The compiler runs locally on Node 24 or newer.
5
+
6
+ ## Files
7
+
8
+ The compiler reads a DTCG resolver and the documents that resolver references.
9
+ It writes `tokens.css`, `tailwind.css`, and `modes.json` into the directory
10
+ from `--out`. Without that flag, the directory is `.generated` beside the resolver.
11
+ The JSON stays the source. Ignore the output directory.
12
+
13
+ ```text
14
+ tokens/tokens.resolver.json sets, modes, default
15
+ tokens/base.json every value for the default context
16
+ tokens/dark.json sparse overrides for one other context
17
+ tokens/.generated/tokens.css custom properties
18
+ tokens/.generated/tailwind.css Tailwind @theme bindings
19
+ tokens/.generated/modes.json context names, selectors, revision
20
+ ```
21
+
22
+ The directory and the JSON filenames are yours. `$ref` inside the resolver
23
+ decides which documents are read. `base.json` and `dark.json` above are only
24
+ an example: one complete document, then a document that overrides existing
25
+ paths for another context. A mode file does not declare types and does not
26
+ add tokens that exist only in that mode.
27
+
28
+ Pass `--entry` to point at the resolver and `--out` to choose the output
29
+ directory. If you omit `--entry`, the CLI uses
30
+ `.reforma/tokens/tokens.resolver.json`. If you omit `--out`, it writes
31
+ `.generated` beside the resolver.
32
+
33
+ `tokens.css` puts the default context on `:root` and each other context on a
34
+ selector such as `html[data-theme="dark"]`. `tailwind.css` is an
35
+ `@theme inline` block. It includes only names Tailwind already treats as theme
36
+ keys, including `color`, `spacing`, `font`, `text`, `radius`, and `shadow`.
37
+ Any other group stays a plain variable in `tokens.css`. `modes.json` records
38
+ the default, each modifier's contexts, the selector for every permutation,
39
+ the input revision, and hashes of the source files.
40
+
41
+ This generated `tailwind.css` is not the project's Tailwind entry. The app
42
+ imports its own Tailwind CSS, then these generated files. `check` writes
43
+ nothing. `build`, `watch`, and `dev` replace the three files when the output
44
+ changes, and leave the last good output in place when the JSON is invalid.
5
45
 
6
46
  ## CLI
7
47
 
8
- Install the package, then call the `reforma-tokens` binary from a script. The default
9
- entry is `.reforma/tokens/tokens.resolver.json`.
48
+ Install the package, then call the `reforma-tokens` binary from a script.
49
+ `--entry` selects the resolver. The default is `.reforma/tokens/tokens.resolver.json`.
10
50
 
11
51
  ```json
12
52
  {
@@ -29,20 +69,16 @@ command.
29
69
  | `dev -- command ...` | Build before starting the command. Watch sources. Forward signals and the exit status. |
30
70
 
31
71
  `--cwd directory` selects the workspace. `--entry path` selects its resolver.
72
+ `--out directory` selects the output directory.
32
73
  Repeat `--context axis=value` to supply contexts, including axes without defaults.
33
74
  Every permutation is validated. The selected or default input supplies `:root`.
34
75
  Names are case-sensitive. Compilation stops at 1000 permutations.
35
76
 
36
- Ignore `.reforma/tokens/.generated/` in Git. A build writes `tokens.css`,
37
- `tailwind.css`, and `modes.json` there, and may leave staging and lock files
38
- while it runs. Import the generated CSS before application styles, and import
39
- `tailwind.css` through the project's Tailwind entry.
40
-
41
- A failed rebuild leaves the last successful output unchanged. Watch and dev print
42
- one JSON diagnostic per line on stderr and `{ "status": "stale", "revision" }`
43
- when input is invalid. A successful rebuild prints `{ "status": "ready", "revision" }`
44
- on stdout. The app keeps running after a bad edit. An invalid first build does
45
- not start the dev command.
77
+ A build may also leave staging and lock files in the output directory while it runs.
78
+ Watch and dev print one JSON diagnostic per line on stderr and
79
+ `{ "status": "stale", "revision" }` when input is invalid. A successful rebuild
80
+ prints `{ "status": "ready", "revision" }` on stdout. The app keeps running after
81
+ a bad edit. An invalid first build does not start the dev command.
46
82
 
47
83
  ## API
48
84
 
package/dist/cli.js CHANGED
@@ -111,11 +111,11 @@ async function main() {
111
111
  const separator = args.indexOf('--');
112
112
  const childCommand = separator < 0 ? [] : args.slice(separator + 1);
113
113
  const { values, positionals } = parseArgs({ args: separator < 0 ? args : args.slice(0, separator), allowPositionals: true, options: {
114
- cwd: { type: 'string' }, entry: { type: 'string' }, context: { type: 'string', multiple: true }, help: { type: 'boolean' },
114
+ cwd: { type: 'string' }, entry: { type: 'string' }, out: { type: 'string' }, context: { type: 'string', multiple: true }, help: { type: 'boolean' },
115
115
  } });
116
116
  const [command] = positionals;
117
117
  if (values.help) {
118
- process.stdout.write('reforma-tokens <build|check|watch|dev -- command...> [--cwd directory] [--entry resolver.json] [--context axis=value]\n');
118
+ process.stdout.write('reforma-tokens <build|check|watch|dev -- command...> [--cwd directory] [--entry resolver.json] [--out directory] [--context axis=value]\n');
119
119
  return;
120
120
  }
121
121
  if (!['build', 'check', 'watch', 'dev'].includes(command ?? '') || positionals.length !== 1)
@@ -129,7 +129,7 @@ async function main() {
129
129
  throw new Error('Expected --context axis=value.');
130
130
  input[context.slice(0, separator)] = context.slice(separator + 1);
131
131
  }
132
- const options = { workspaceRoot: await realpath(resolve(values.cwd ?? process.cwd())), entry: values.entry, input };
132
+ const options = { workspaceRoot: await realpath(resolve(values.cwd ?? process.cwd())), entry: values.entry, out: values.out, input };
133
133
  if (command === 'watch' || command === 'dev')
134
134
  return watch(options, childCommand);
135
135
  const result = await (command === 'check' ? compileProjectTokens(options) : buildProjectTokens(options));
@@ -38,6 +38,8 @@ export interface TokenPermutation {
38
38
  export interface TokenCompilationOptions {
39
39
  workspaceRoot: string;
40
40
  entry?: string;
41
+ /** Directory for generated CSS and mode metadata. Defaults to `.generated` beside the resolver. */
42
+ out?: string;
41
43
  /** Required values for modifiers without a default. */
42
44
  input?: Record<string, string>;
43
45
  /** In-memory candidate files, keyed by workspace-relative path. Never persisted by compilation. */
@@ -1 +1 @@
1
- {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/compilation/compiler.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEtG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,mGAAmG;IACnG,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAUD,mFAAmF;AACnF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiStG"}
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/compilation/compiler.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEtG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,cAAc,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mGAAmG;IACnG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,mGAAmG;IACnG,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAUD,mFAAmF;AACnF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiStG"}
@@ -1 +1 @@
1
- {"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../src/generation.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwB,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAYtH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,0BAYnE;AAED,wBAAsB,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,gBAAgB,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoIxL;AAED,0FAA0F;AAC1F,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEpG"}
1
+ {"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../src/generation.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwB,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAYtH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,0BAYnE;AAOD,wBAAsB,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,gBAAgB,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoIxL;AAED,0FAA0F;AAC1F,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEpG"}
@@ -28,9 +28,14 @@ export async function readTokenDependency(root, path) {
28
28
  throw error;
29
29
  }
30
30
  }
31
+ function generatedDirectory(root, options) {
32
+ if (options.out)
33
+ return resolve(root, options.out);
34
+ return resolve(root, dirname(options.entry ?? '.reforma/tokens/tokens.resolver.json'), '.generated');
35
+ }
31
36
  export async function withTokenCompilationLock(options, work) {
32
37
  const root = await realpath(options.workspaceRoot);
33
- const directory = resolve(root, dirname(options.entry ?? '.reforma/tokens/tokens.resolver.json'), '.generated');
38
+ const directory = generatedDirectory(root, options);
34
39
  // Check every existing ancestor before creating output or following a symlink.
35
40
  for (let path = directory; path !== root; path = dirname(path)) {
36
41
  const rel = relative(root, path);
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@reforma/project-tokens",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Portable DTCG 2025.10 compiler for project design tokens.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "author": "Reforma, Inc. <dev@reforma.ai>",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/reforma-dev/reforma",
10
+ "url": "https://github.com/reforma-ai/reforma",
11
11
  "directory": "packages/project-tokens"
12
12
  },
13
13
  "exports": {