@terrazzo/cli 2.0.0-beta.6 → 2.0.0-rc.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 CHANGED
@@ -77,9 +77,9 @@ The 2.0.0 release is full of new features:
77
77
 
78
78
  - [#568](https://github.com/terrazzoapp/terrazzo/pull/568) [`67c75be`](https://github.com/terrazzoapp/terrazzo/commit/67c75be78978cece52b61cf258ccc3a875e6af48) Thanks [@drwpow](https://github.com/drwpow)! - Fix border tokens not cascading correctly across modes
79
79
 
80
- - An error is now thrown if `--config [path]` points to a bad location.
80
+ - Bugfix: An error is now thrown if `--config [path]` points to a bad location.
81
81
 
82
- - TypeScript config files now fully supported! `terrazzo.config.ts` is now the default.
82
+ - Config: TypeScript files and plugins are now fully supported! `terrazzo.config.ts` is now the default.
83
83
 
84
84
  ## 0.10.3
85
85
 
package/bin/cli.js CHANGED
@@ -32,12 +32,12 @@ import { Logger } from '@terrazzo/parser';
32
32
  import {
33
33
  buildCmd,
34
34
  checkCmd,
35
+ formatCmd,
35
36
  helpCmd,
36
37
  importCmd,
37
38
  initCmd,
38
39
  labCmd,
39
40
  loadConfig,
40
- normalizeCmd,
41
41
  versionCmd,
42
42
  } from '../dist/index.js';
43
43
 
@@ -113,9 +113,9 @@ export default async function main() {
113
113
  process.exit(0);
114
114
  }
115
115
 
116
- // normalize
117
- if (cmd === 'normalize') {
118
- await normalizeCmd(positionals[1], { logger, output: flags.output });
116
+ // format
117
+ if (cmd === 'format' || cmd === 'normalize') {
118
+ await formatCmd(positionals[1], { logger, output: flags.output });
119
119
  process.exit(0);
120
120
  }
121
121
  // import
package/dist/index.d.ts CHANGED
@@ -93,6 +93,16 @@ declare function checkCmd({
93
93
  positionals
94
94
  }: CheckOptions): Promise<void>;
95
95
  //#endregion
96
+ //#region src/format.d.ts
97
+ interface NormalizeOptions {
98
+ logger: Logger;
99
+ output: URL;
100
+ }
101
+ declare function formatCmd(filename: string, {
102
+ logger,
103
+ output
104
+ }: NormalizeOptions): Promise<void>;
105
+ //#endregion
96
106
  //#region src/help.d.ts
97
107
  /** Show help */
98
108
  declare function helpCmd(): void;
@@ -165,21 +175,11 @@ declare function labCmd({
165
175
  logger
166
176
  }: LabBuildOptions): Promise<void>;
167
177
  //#endregion
168
- //#region src/normalize.d.ts
169
- interface NormalizeOptions {
170
- logger: Logger;
171
- output: URL;
172
- }
173
- declare function normalizeCmd(filename: string, {
174
- logger,
175
- output
176
- }: NormalizeOptions): Promise<void>;
177
- //#endregion
178
178
  //#region src/version.d.ts
179
179
  declare function versionCmd(): void;
180
180
  //#endregion
181
181
  //#region src/index.d.ts
182
182
  declare function defineConfig(config: Config): ConfigInit;
183
183
  //#endregion
184
- export { BuildOptions, CheckOptions, Command, DEFAULT_CONFIG_PATH, DEFAULT_TOKENS_PATH, FigmaOutput, Flags, GREEN_CHECK, ImportCmdOptions, InitOptions, LabBuildOptions, LoadConfigOptions, NormalizeOptions, buildCmd, checkCmd, cwd, defineConfig, helpCmd, importCmd, importFromFigma, importFromFigmaOptions, initCmd, isFigmaPath, labCmd, loadConfig, loadTokens, normalizeCmd, printError, printSuccess, resolveConfig, resolveTokenPath, time, versionCmd, writeFiles };
184
+ export { BuildOptions, CheckOptions, Command, DEFAULT_CONFIG_PATH, DEFAULT_TOKENS_PATH, FigmaOutput, Flags, GREEN_CHECK, ImportCmdOptions, InitOptions, LabBuildOptions, LoadConfigOptions, NormalizeOptions, buildCmd, checkCmd, cwd, defineConfig, formatCmd, helpCmd, importCmd, importFromFigma, importFromFigmaOptions, initCmd, isFigmaPath, labCmd, loadConfig, loadTokens, printError, printSuccess, resolveConfig, resolveTokenPath, time, versionCmd, writeFiles };
185
185
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/shared.ts","../src/build.ts","../src/check.ts","../src/help.ts","../src/import/figma/index.ts","../src/import/index.ts","../src/init.ts","../src/lab.ts","../src/normalize.ts","../src/version.ts","../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/shared.ts","../src/build.ts","../src/check.ts","../src/format.ts","../src/help.ts","../src/import/figma/index.ts","../src/import/index.ts","../src/init.ts","../src/lab.ts","../src/version.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
+ import fsSync from "node:fs";
2
3
  import { fileURLToPath, pathToFileURL } from "node:url";
3
4
  import { build, defineConfig as defineConfig$1, parse } from "@terrazzo/parser";
4
- import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import pc from "picocolors";
7
7
  import { createServer } from "vite";
@@ -9,8 +9,11 @@ import { ViteNodeRunner } from "vite-node/client";
9
9
  import { ViteNodeServer } from "vite-node/server";
10
10
  import chokidar from "chokidar";
11
11
  import yamlToMomoa from "yaml-to-momoa";
12
- import fs$1 from "node:fs/promises";
12
+ import * as momoa from "@humanwhocodes/momoa";
13
+ import { getObjMember, getObjMembers, traverse } from "@terrazzo/json-schema-tools";
13
14
  import { isAlias, pluralize } from "@terrazzo/token-tools";
15
+ import yaml from "yaml";
16
+ import fs from "node:fs/promises";
14
17
  import { merge } from "merge-anything";
15
18
  import { camelCase } from "scule";
16
19
  import { spawn } from "node:child_process";
@@ -21,8 +24,6 @@ import { parseModule } from "meriyah";
21
24
  import { Readable, Writable } from "node:stream";
22
25
  import { serve } from "@hono/node-server";
23
26
  import mime from "mime";
24
- import * as momoa from "@humanwhocodes/momoa";
25
- import { getObjMember, getObjMembers, traverse } from "@terrazzo/json-schema-tools";
26
27
 
27
28
  //#region src/shared.ts
28
29
  const cwd = new URL(`${pathToFileURL(process.cwd())}/`);
@@ -115,9 +116,9 @@ async function loadTokens(tokenPaths, { logger }) {
115
116
  message: `loadTokens: Expected array, received ${typeof tokenPaths}`
116
117
  });
117
118
  if (tokenPaths.length === 1 && tokenPaths[0].href === DEFAULT_TOKENS_PATH.href) {
118
- if (!fs.existsSync(tokenPaths[0])) {
119
+ if (!fsSync.existsSync(tokenPaths[0])) {
119
120
  const yamlPath = new URL("./tokens.yaml", cwd);
120
- if (fs.existsSync(yamlPath)) tokenPaths[0] = yamlPath;
121
+ if (fsSync.existsSync(yamlPath)) tokenPaths[0] = yamlPath;
121
122
  else {
122
123
  logger.error({
123
124
  group: "config",
@@ -185,9 +186,9 @@ async function loadTokens(tokenPaths, { logger }) {
185
186
  });
186
187
  return;
187
188
  }
188
- else if (fs.existsSync(filename)) allTokens.push({
189
+ else if (fsSync.existsSync(filename)) allTokens.push({
189
190
  filename,
190
- src: fs.readFileSync(filename, "utf8")
191
+ src: fsSync.readFileSync(filename, "utf8")
191
192
  });
192
193
  else {
193
194
  logger.error({
@@ -213,7 +214,7 @@ function printSuccess(message, startTime) {
213
214
  }
214
215
  /** Resolve config */
215
216
  function resolveConfig(filename) {
216
- if (filename && fs.existsSync(new URL(filename, cwd))) return filename;
217
+ if (filename && fsSync.existsSync(new URL(filename, cwd))) return filename;
217
218
  for (const ext of [
218
219
  ".ts",
219
220
  ".js",
@@ -223,17 +224,17 @@ function resolveConfig(filename) {
223
224
  ".cjs"
224
225
  ]) {
225
226
  const maybeFilename = `terrazzo.config${ext}`;
226
- if (fs.existsSync(new URL(maybeFilename, cwd))) return fileURLToPath(new URL(maybeFilename, cwd));
227
+ if (fsSync.existsSync(new URL(maybeFilename, cwd))) return fileURLToPath(new URL(maybeFilename, cwd));
227
228
  }
228
229
  }
229
230
  /** Resolve tokens.json path (for lint command) */
230
231
  function resolveTokenPath(filename, { logger }) {
231
232
  const tokensPath = new URL(filename, cwd);
232
- if (!fs.existsSync(tokensPath)) logger.error({
233
+ if (!fsSync.existsSync(tokensPath)) logger.error({
233
234
  group: "config",
234
235
  message: `Could not locate ${filename}. Does the file exist?`
235
236
  });
236
- else if (!fs.statSync(tokensPath).isFile()) logger.error({
237
+ else if (!fsSync.statSync(tokensPath).isFile()) logger.error({
237
238
  group: "config",
238
239
  message: `Expected JSON or YAML file, received ${filename}.`
239
240
  });
@@ -336,8 +337,8 @@ async function buildCmd({ config, configPath, flags, logger }) {
336
337
  function writeFiles(result, { config, logger }) {
337
338
  for (const { filename, contents } of result.outputFiles) {
338
339
  const output = new URL(filename, config.outDir);
339
- fs.mkdirSync(new URL(".", output), { recursive: true });
340
- fs.writeFileSync(output, contents);
340
+ fsSync.mkdirSync(new URL(".", output), { recursive: true });
341
+ fsSync.writeFileSync(output, contents);
341
342
  logger.debug({
342
343
  group: "parser",
343
344
  label: "buildEnd",
@@ -373,6 +374,125 @@ async function checkCmd({ config, logger, positionals }) {
373
374
  }
374
375
  }
375
376
 
377
+ //#endregion
378
+ //#region src/format.ts
379
+ function findMember(name) {
380
+ return function(member) {
381
+ return member.name.type === "String" && member.name.value === name;
382
+ };
383
+ }
384
+ async function formatCmd(filename, { logger, output }) {
385
+ try {
386
+ if (!filename) {
387
+ logger.error({
388
+ group: "config",
389
+ message: "Expected input: `tz format <tokens.json> -o output.json`"
390
+ });
391
+ return;
392
+ }
393
+ const sourceLoc = new URL(filename, cwd);
394
+ if (!fsSync.existsSync(sourceLoc)) logger.error({
395
+ group: "config",
396
+ message: `Couldn’t find ${path.relative(cwd.href, sourceLoc.href)}. Does it exist?`
397
+ });
398
+ const sourceData = fsSync.readFileSync(sourceLoc, "utf8");
399
+ const isYaml = filename.endsWith(".yml") || filename.endsWith(".yaml") || !sourceData.startsWith("{");
400
+ const document = isYaml ? yamlToMomoa(sourceData) : momoa.parse(sourceData, { mode: "jsonc" });
401
+ const { tokens } = await parse([{
402
+ src: sourceData,
403
+ filename: sourceLoc
404
+ }], {
405
+ config: defineConfig$1({ lint: { rules: {
406
+ "core/consistent-naming": "off",
407
+ "core/valid-color": "off",
408
+ "core/valid-dimension": "off",
409
+ "core/valid-duration": "off",
410
+ "core/valid-typography": "off"
411
+ } } }, { cwd }),
412
+ logger,
413
+ resolveAliases: false,
414
+ yamlToMomoa
415
+ });
416
+ traverse(document, { enter(node, _parent, nodePath) {
417
+ const token = tokens[nodePath.join(".")];
418
+ if (!token || token.aliasOf || node.type !== "Member" || node.value.type !== "Object") return;
419
+ const $valueI = node.value.members.findIndex(findMember("$value"));
420
+ switch (token.$type) {
421
+ case "color":
422
+ if (node.value.members[$valueI].value.type === "String") {
423
+ if (isAlias(node.value.members[$valueI].value.value)) return;
424
+ const hex = node.value.members[$valueI].value.value;
425
+ node.value.members[$valueI].value = momoa.parse(JSON.stringify({
426
+ ...token.$value,
427
+ hex: hex.startsWith("#") ? hex.slice(0, 7) : void 0
428
+ })).body;
429
+ const $extensions = getObjMember(node.value, "$extensions");
430
+ if ($extensions?.type === "Object") {
431
+ const mode = getObjMember($extensions, "mode");
432
+ if (mode?.type === "Object") for (let i = 0; i < mode.members.length; i++) {
433
+ const modeName = mode.members[i].name.value;
434
+ const hex = mode.members[i].value.value;
435
+ mode.members[i].value = momoa.parse(JSON.stringify({
436
+ ...token.mode[modeName].$value,
437
+ hex: hex.startsWith("#") ? hex.slice(0, 7) : void 0
438
+ })).body;
439
+ }
440
+ }
441
+ }
442
+ break;
443
+ case "dimension":
444
+ case "duration":
445
+ if (node.value.members[$valueI].value.type === "String") {
446
+ if (isAlias(node.value.members[$valueI].value.value)) return;
447
+ node.value.members[$valueI].value = formatDurationDimension(node.value.members[$valueI].value);
448
+ const $extensions = getObjMember(node.value, "$extensions");
449
+ if ($extensions?.type === "Object") {
450
+ const mode = getObjMember($extensions, "mode");
451
+ if (mode?.type === "Object") for (let i = 0; i < mode.members.length; i++) mode.members[i].value = formatDurationDimension(node.value.members[$valueI].value);
452
+ }
453
+ }
454
+ break;
455
+ case "typography": {
456
+ if (node.value.members[$valueI]?.value.type !== "Object") return;
457
+ node.value.members[$valueI].value = formatTypography(node.value.members[$valueI].value);
458
+ const $extensions = getObjMember(node.value, "$extensions");
459
+ if ($extensions?.type === "Object") {
460
+ const mode = getObjMember($extensions, "mode");
461
+ if (mode?.type === "Object") for (let i = 0; i < mode.members.length; i++) mode.members[i].value = formatTypography(mode.members[i].value);
462
+ }
463
+ }
464
+ }
465
+ } });
466
+ const outputLoc = new URL(output, cwd);
467
+ const contents = isYaml ? yaml.stringify(JSON.parse(momoa.print(document))) : momoa.print(document, { indent: 2 });
468
+ fsSync.mkdirSync(new URL(".", outputLoc), { recursive: true });
469
+ fsSync.writeFileSync(outputLoc, contents);
470
+ } catch (err) {
471
+ printError(err.message);
472
+ process.exit(1);
473
+ }
474
+ }
475
+ function formatDurationDimension(node) {
476
+ const value = Number.parseFloat(node.value);
477
+ if (!Number.isFinite(value)) return node;
478
+ node.type = "Object";
479
+ node.members = momoa.parse(JSON.stringify({
480
+ value,
481
+ unit: node.value.replace(String(value), "")
482
+ })).body.members;
483
+ delete node.value;
484
+ return node;
485
+ }
486
+ function formatTypography(node) {
487
+ const { fontFamily, fontSize, fontWeight, letterSpacing, lineHeight } = getObjMembers(node);
488
+ if (!fontFamily) node.members.push(momoa.parse("{\"fontFamily\":[\"inherit\"]}").body.members[0]);
489
+ if (!fontSize) node.members.push(momoa.parse("{\"fontSize\":{\"value\":1,\"unit\":\"rem\"}}").body.members[0]);
490
+ if (!fontWeight) node.members.push(momoa.parse("{\"fontWeight\":400}").body.members[0]);
491
+ if (!letterSpacing) node.members.push(momoa.parse("{\"letterSpacing\":{\"value\":0,\"unit\":\"rem\"}}").body.members[0]);
492
+ if (!lineHeight) node.members.push(momoa.parse("{\"lineHeight\":1}").body.members[0]);
493
+ return node;
494
+ }
495
+
376
496
  //#endregion
377
497
  //#region src/help.ts
378
498
  /** Show help */
@@ -384,6 +504,9 @@ function helpCmd() {
384
504
  --no-lint Disable linters running on build
385
505
  check [path] Check tokens.json for errors and run linters
386
506
  lint [path] (alias of check)
507
+ format [path] Format your tokens
508
+ --o [file] Output file
509
+ normalize (alias of format)
387
510
  init Create a starter tokens.json file
388
511
  lab Manage your tokens with a web interface
389
512
  import [path] Import from a Figma Design file
@@ -936,7 +1059,7 @@ async function importCmd({ flags, positionals, logger }) {
936
1059
  });
937
1060
  const end = performance.now() - start;
938
1061
  if (flags.output) {
939
- const oldFile = fs.existsSync(flags.output) ? JSON.parse(await fs$1.readFile(flags.output, "utf8")) : {};
1062
+ const oldFile = fsSync.existsSync(flags.output) ? JSON.parse(await fs.readFile(flags.output, "utf8")) : {};
940
1063
  const code = {
941
1064
  $schema: result.code.$schema,
942
1065
  version: result.code.version,
@@ -946,7 +1069,7 @@ async function importCmd({ flags, positionals, logger }) {
946
1069
  $defs: oldFile.$defs,
947
1070
  $extensions: oldFile.$extensions
948
1071
  };
949
- await fs$1.writeFile(flags.output, `${JSON.stringify(code, void 0, 2)}\n`);
1072
+ await fs.writeFile(flags.output, `${JSON.stringify(code, void 0, 2)}\n`);
950
1073
  logger.info({
951
1074
  group: "import",
952
1075
  message: `Imported ${formatNumber(result.variableCount)} ${pluralize(result.variableCount, "Variable", "Variables")}, ${formatNumber(result.styleCount)} ${pluralize(result.styleCount, "Style", "Styles")} → ${flags.output}`,
@@ -1018,9 +1141,9 @@ async function initCmd({ logger }) {
1018
1141
  logger
1019
1142
  });
1020
1143
  const tokensPath = config.tokens[0];
1021
- const hasExistingConfig = fs.existsSync(configPath);
1022
- let startFromDS = !(tokensPath && fs.existsSync(tokensPath));
1023
- if (tokensPath && fs.existsSync(tokensPath)) {
1144
+ const hasExistingConfig = fsSync.existsSync(configPath);
1145
+ let startFromDS = !(tokensPath && fsSync.existsSync(tokensPath));
1146
+ if (tokensPath && fsSync.existsSync(tokensPath)) {
1024
1147
  if (await confirm({ message: `Found tokens at ${path.relative(fileURLToPath(cwd), fileURLToPath(tokensPath))}. Overwrite with a new design system?` })) startFromDS = true;
1025
1148
  }
1026
1149
  if (startFromDS) {
@@ -1049,7 +1172,7 @@ async function initCmd({ logger }) {
1049
1172
  }
1050
1173
  if (!hasExistingConfig) {
1051
1174
  await newConfigFile(configPath, [EXAMPLE_TOKENS_PATH]);
1052
- await fs$1.writeFile(EXAMPLE_TOKENS_PATH, JSON.stringify(EXAMPLE_TOKENS, void 0, 2));
1175
+ await fs.writeFile(EXAMPLE_TOKENS_PATH, JSON.stringify(EXAMPLE_TOKENS, void 0, 2));
1053
1176
  }
1054
1177
  const existingPlugins = config.plugins.map((p) => p.name);
1055
1178
  const pluginSelection = await multiselect({
@@ -1103,7 +1226,7 @@ async function initCmd({ logger }) {
1103
1226
  }
1104
1227
  }
1105
1228
  async function newConfigFile(configPath, tokens, imports = []) {
1106
- await fs$1.writeFile(configPath, `import { defineConfig } from '@terrazzo/cli';
1229
+ await fs.writeFile(configPath, `import { defineConfig } from '@terrazzo/cli';
1107
1230
  ${imports.map((p) => `import ${p.specifier} from '${p.path}';`).join("\n")}
1108
1231
 
1109
1232
  export default defineConfig({
@@ -1150,7 +1273,7 @@ function getConfigObjFromAst(ast, configPath) {
1150
1273
  return astConfig;
1151
1274
  }
1152
1275
  async function updateConfigTokens(configPath, tokens) {
1153
- const ast = parseModule(await fs$1.readFile(configPath, "utf8"));
1276
+ const ast = parseModule(await fs.readFile(configPath, "utf8"));
1154
1277
  const astConfig = getConfigObjFromAst(ast, configPath);
1155
1278
  let tokensKey = astConfig.properties.find((p) => p.type === "Property" && p.key.type === "Identifier" && p.key.name === "tokens");
1156
1279
  if (!tokensKey) {
@@ -1174,7 +1297,7 @@ async function updateConfigTokens(configPath, tokens) {
1174
1297
  };
1175
1298
  astConfig.properties.unshift(tokensKey);
1176
1299
  }
1177
- await fs$1.writeFile(configPath, generate(ast, SYNTAX_SETTINGS));
1300
+ await fs.writeFile(configPath, generate(ast, SYNTAX_SETTINGS));
1178
1301
  }
1179
1302
  /**
1180
1303
  * Add plugin imports
@@ -1185,7 +1308,7 @@ async function updateConfigTokens(configPath, tokens) {
1185
1308
  * introduce bugs).
1186
1309
  */
1187
1310
  async function updateConfigPlugins(configPath, plugins) {
1188
- const ast = parseModule(await fs$1.readFile(configPath, "utf8"));
1311
+ const ast = parseModule(await fs.readFile(configPath, "utf8"));
1189
1312
  ast.body.push(...plugins.map((p) => ({
1190
1313
  type: "ImportDeclaration",
1191
1314
  source: {
@@ -1228,7 +1351,7 @@ async function updateConfigPlugins(configPath, plugins) {
1228
1351
  method: false,
1229
1352
  shorthand: false
1230
1353
  });
1231
- await fs$1.writeFile(configPath, generate(ast, SYNTAX_SETTINGS));
1354
+ await fs.writeFile(configPath, generate(ast, SYNTAX_SETTINGS));
1232
1355
  }
1233
1356
  const EXAMPLE_TOKENS = {
1234
1357
  color: {
@@ -1418,7 +1541,7 @@ async function labCmd({ config, logger }) {
1418
1541
  /** TODO: handle multiple files */
1419
1542
  const [tokenFileUrl] = config.tokens;
1420
1543
  const staticFiles = /* @__PURE__ */ new Set();
1421
- const dirEntries = await fs$1.readdir(fileURLToPath(import.meta.resolve("./lab")), {
1544
+ const dirEntries = await fs.readdir(fileURLToPath(import.meta.resolve("./lab")), {
1422
1545
  withFileTypes: true,
1423
1546
  recursive: true
1424
1547
  });
@@ -1432,18 +1555,18 @@ async function labCmd({ config, logger }) {
1432
1555
  overrideGlobalObjects: false,
1433
1556
  async fetch(request) {
1434
1557
  const pathname = new URL(request.url).pathname;
1435
- if (pathname === "/") return new Response(Readable.toWeb(fs.createReadStream(fileURLToPath(import.meta.resolve("./lab/index.html")))), { headers: { "Content-Type": "text/html" } });
1558
+ if (pathname === "/") return new Response(Readable.toWeb(fsSync.createReadStream(fileURLToPath(import.meta.resolve("./lab/index.html")))), { headers: { "Content-Type": "text/html" } });
1436
1559
  if (pathname === "/api/tokens") {
1437
- if (request.method === "GET") return new Response(Readable.toWeb(fs.createReadStream(tokenFileUrl)), { headers: {
1560
+ if (request.method === "GET") return new Response(Readable.toWeb(fsSync.createReadStream(tokenFileUrl)), { headers: {
1438
1561
  "Content-Type": "application/json",
1439
1562
  "Cache-Control": "no-cache"
1440
1563
  } });
1441
1564
  else if (request.method === "POST" && request.body) {
1442
- await request.body.pipeTo(Writable.toWeb(fs.createWriteStream(tokenFileUrl)));
1565
+ await request.body.pipeTo(Writable.toWeb(fsSync.createWriteStream(tokenFileUrl)));
1443
1566
  return new Response(JSON.stringify({ success: true }), { headers: { "Content-Type": "application/json" } });
1444
1567
  }
1445
1568
  }
1446
- if (staticFiles.has(pathname)) return new Response(Readable.toWeb(fs.createReadStream(fileURLToPath(import.meta.resolve(`./lab${pathname}`)))), { headers: { "Content-Type": mime.getType(pathname) ?? "application/octet-stream" } });
1569
+ if (staticFiles.has(pathname)) return new Response(Readable.toWeb(fsSync.createReadStream(fileURLToPath(import.meta.resolve(`./lab${pathname}`)))), { headers: { "Content-Type": mime.getType(pathname) ?? "application/octet-stream" } });
1447
1570
  return new Response("Not found", { status: 404 });
1448
1571
  }
1449
1572
  }, (info) => {
@@ -1461,124 +1584,10 @@ async function labCmd({ config, logger }) {
1461
1584
  });
1462
1585
  }
1463
1586
 
1464
- //#endregion
1465
- //#region src/normalize.ts
1466
- function findMember(name) {
1467
- return function(member) {
1468
- return member.name.type === "String" && member.name.value === name;
1469
- };
1470
- }
1471
- async function normalizeCmd(filename, { logger, output }) {
1472
- try {
1473
- if (!filename) {
1474
- logger.error({
1475
- group: "config",
1476
- message: "Expected input: `tz normalize <tokens.json> -o output.json`"
1477
- });
1478
- return;
1479
- }
1480
- const sourceLoc = new URL(filename, cwd);
1481
- if (!fs.existsSync(sourceLoc)) logger.error({
1482
- group: "config",
1483
- message: `Couldn’t find ${path.relative(cwd.href, sourceLoc.href)}. Does it exist?`
1484
- });
1485
- const sourceData = fs.readFileSync(sourceLoc, "utf8");
1486
- const document = momoa.parse(sourceData, { mode: "jsonc" });
1487
- const { tokens } = await parse([{
1488
- src: sourceData,
1489
- filename: sourceLoc
1490
- }], {
1491
- config: defineConfig$1({ lint: { rules: {
1492
- "core/valid-color": "off",
1493
- "core/valid-dimension": "off",
1494
- "core/valid-duration": "off",
1495
- "core/valid-typography": "off"
1496
- } } }, { cwd }),
1497
- logger
1498
- });
1499
- traverse(document, { enter(node, _parent, nodePath) {
1500
- const token = tokens[nodePath.join(".")];
1501
- if (!token || token.aliasOf || node.type !== "Member" || node.value.type !== "Object") return;
1502
- const $valueI = node.value.members.findIndex(findMember("$value"));
1503
- switch (token.$type) {
1504
- case "color":
1505
- if (node.value.members[$valueI].value.type === "String") {
1506
- if (isAlias(node.value.members[$valueI].value.value)) return;
1507
- const hex = node.value.members[$valueI].value.value;
1508
- node.value.members[$valueI].value = momoa.parse(JSON.stringify({
1509
- ...token.$value,
1510
- hex: hex.startsWith("#") ? hex.slice(0, 7) : void 0
1511
- })).body;
1512
- const $extensions = getObjMember(node.value, "$extensions");
1513
- if ($extensions?.type === "Object") {
1514
- const mode = getObjMember($extensions, "mode");
1515
- if (mode?.type === "Object") for (let i = 0; i < mode.members.length; i++) {
1516
- const modeName = mode.members[i].name.value;
1517
- const hex = mode.members[i].value.value;
1518
- mode.members[i].value = momoa.parse(JSON.stringify({
1519
- ...token.mode[modeName].$value,
1520
- hex: hex.startsWith("#") ? hex.slice(0, 7) : void 0
1521
- })).body;
1522
- }
1523
- }
1524
- }
1525
- break;
1526
- case "dimension":
1527
- case "duration":
1528
- if (node.value.members[$valueI].value.type === "String") {
1529
- if (isAlias(node.value.members[$valueI].value.value)) return;
1530
- node.value.members[$valueI].value = normalizeDurationDimension(node.value.members[$valueI].value);
1531
- const $extensions = getObjMember(node.value, "$extensions");
1532
- if ($extensions?.type === "Object") {
1533
- const mode = getObjMember($extensions, "mode");
1534
- if (mode?.type === "Object") for (let i = 0; i < mode.members.length; i++) mode.members[i].value = normalizeDurationDimension(node.value.members[$valueI].value);
1535
- }
1536
- }
1537
- break;
1538
- case "typography": {
1539
- if (node.value.members[$valueI]?.value.type !== "Object") return;
1540
- node.value.members[$valueI].value = normalizeTypography(node.value.members[$valueI].value);
1541
- const $extensions = getObjMember(node.value, "$extensions");
1542
- if ($extensions?.type === "Object") {
1543
- const mode = getObjMember($extensions, "mode");
1544
- if (mode?.type === "Object") for (let i = 0; i < mode.members.length; i++) mode.members[i].value = normalizeTypography(mode.members[i].value);
1545
- }
1546
- }
1547
- }
1548
- } });
1549
- const outputLoc = new URL(output, cwd);
1550
- fs.mkdirSync(new URL(".", outputLoc), { recursive: true });
1551
- fs.writeFileSync(outputLoc, momoa.print(document, { indent: 2 }));
1552
- } catch (err) {
1553
- printError(err.message);
1554
- process.exit(1);
1555
- }
1556
- }
1557
- function normalizeDurationDimension(node) {
1558
- const value = Number.parseFloat(node.value);
1559
- if (!Number.isFinite(value)) return node;
1560
- node.type = "Object";
1561
- node.members = momoa.parse(JSON.stringify({
1562
- value,
1563
- unit: node.value.replace(String(value), "")
1564
- })).body.members;
1565
- delete node.value;
1566
- return node;
1567
- }
1568
- function normalizeTypography(node) {
1569
- const { fontFamily, fontSize, fontWeight, letterSpacing, lineHeight } = getObjMembers(node);
1570
- if (!fontFamily) node.members.push(momoa.parse("{\"fontFamily\":[\"inherit\"]}").body.members[0]);
1571
- if (!fontSize) node.members.push(momoa.parse("{\"fontSize\":{\"value\":1,\"unit\":\"rem\"}}").body.members[0]);
1572
- if (!fontWeight) node.members.push(momoa.parse("{\"fontWeight\":400}").body.members[0]);
1573
- if (!letterSpacing) node.members.push(momoa.parse("{\"letterSpacing\":{\"value\":0,\"unit\":\"rem\"}}").body.members[0]);
1574
- if (!lineHeight) node.members.push(momoa.parse("{\"lineHeight\":1}").body.members[0]);
1575
- return node;
1576
- }
1577
-
1578
1587
  //#endregion
1579
1588
  //#region src/version.ts
1580
1589
  function versionCmd() {
1581
- const { version } = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
1590
+ const { version } = JSON.parse(fsSync.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
1582
1591
  console.log(version);
1583
1592
  }
1584
1593
 
@@ -1589,6 +1598,7 @@ function defineConfig(config) {
1589
1598
  const normalizedConfig = { ...config };
1590
1599
  if (typeof normalizedConfig.tokens === "string" || Array.isArray(normalizedConfig.tokens)) normalizedConfig.tokens = (Array.isArray(normalizedConfig.tokens) ? normalizedConfig.tokens : [normalizedConfig.tokens]).map((tokenPath) => {
1591
1600
  if (tokenPath.startsWith(".") || /^(https?|file):\/\//i.test(tokenPath)) return tokenPath;
1601
+ else if (fsSync.existsSync(new URL(tokenPath, cwd))) return new URL(tokenPath, cwd);
1592
1602
  try {
1593
1603
  return pathToFileURL(require.resolve(tokenPath));
1594
1604
  } catch (err) {
@@ -1600,5 +1610,5 @@ function defineConfig(config) {
1600
1610
  }
1601
1611
 
1602
1612
  //#endregion
1603
- export { DEFAULT_CONFIG_PATH, DEFAULT_TOKENS_PATH, GREEN_CHECK, buildCmd, checkCmd, cwd, defineConfig, helpCmd, importCmd, importFromFigma, initCmd, isFigmaPath, labCmd, loadConfig, loadTokens, normalizeCmd, printError, printSuccess, resolveConfig, resolveTokenPath, time, versionCmd, writeFiles };
1613
+ export { DEFAULT_CONFIG_PATH, DEFAULT_TOKENS_PATH, GREEN_CHECK, buildCmd, checkCmd, cwd, defineConfig, formatCmd, helpCmd, importCmd, importFromFigma, initCmd, isFigmaPath, labCmd, loadConfig, loadTokens, printError, printSuccess, resolveConfig, resolveTokenPath, time, versionCmd, writeFiles };
1604
1614
  //# sourceMappingURL=index.js.map