@digdir/designsystemet 1.12.1 → 1.13.1

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 (43) hide show
  1. package/dist/bin/config.d.ts +4 -4
  2. package/dist/bin/config.d.ts.map +1 -1
  3. package/dist/bin/config.js +133 -28
  4. package/dist/bin/designsystemet.d.ts.map +1 -1
  5. package/dist/bin/designsystemet.js +279 -238
  6. package/dist/src/config.d.ts +2 -2
  7. package/dist/src/config.d.ts.map +1 -1
  8. package/dist/src/config.js +4 -4
  9. package/dist/src/index.js +5 -5
  10. package/dist/src/migrations/beta-to-v1.js +122 -16
  11. package/dist/src/migrations/codemods/css/run.d.ts.map +1 -1
  12. package/dist/src/migrations/codemods/css/run.js +122 -16
  13. package/dist/src/migrations/color-rename-next49.js +122 -16
  14. package/dist/src/migrations/index.js +122 -16
  15. package/dist/src/scripts/update-preview-tokens.d.ts.map +1 -1
  16. package/dist/src/scripts/update-preview-tokens.js +122 -45
  17. package/dist/src/tokens/build.d.ts +2 -1
  18. package/dist/src/tokens/build.d.ts.map +1 -1
  19. package/dist/src/tokens/build.js +128 -62
  20. package/dist/src/tokens/create/files.d.ts +11 -0
  21. package/dist/src/tokens/create/files.d.ts.map +1 -0
  22. package/dist/src/tokens/create/{write.js → files.js} +143 -83
  23. package/dist/src/tokens/create/generators/$designsystemet.js +5 -5
  24. package/dist/src/tokens/format.js +5 -5
  25. package/dist/src/tokens/generate-config.d.ts +0 -1
  26. package/dist/src/tokens/generate-config.d.ts.map +1 -1
  27. package/dist/src/tokens/generate-config.js +145 -26
  28. package/dist/src/tokens/index.js +5 -5
  29. package/dist/src/tokens/process/output/declarations.js +5 -5
  30. package/dist/src/tokens/process/output/theme.js +5 -5
  31. package/dist/src/tokens/process/platform.d.ts +0 -4
  32. package/dist/src/tokens/process/platform.d.ts.map +1 -1
  33. package/dist/src/tokens/types.d.ts +2 -0
  34. package/dist/src/tokens/types.d.ts.map +1 -1
  35. package/dist/src/utils/filesystem.d.ts +40 -0
  36. package/dist/src/utils/filesystem.d.ts.map +1 -0
  37. package/dist/src/utils/filesystem.js +127 -0
  38. package/package.json +6 -6
  39. package/dist/src/tokens/create/write.d.ts +0 -12
  40. package/dist/src/tokens/create/write.d.ts.map +0 -1
  41. package/dist/src/utils.d.ts +0 -18
  42. package/dist/src/utils.d.ts.map +0 -1
  43. package/dist/src/utils.js +0 -70
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // bin/designsystemet.ts
4
+ import path4 from "path";
4
5
  import { Argument, createCommand, program } from "@commander-js/extra-typings";
5
- import pc12 from "picocolors";
6
- import * as R29 from "ramda";
6
+ import pc11 from "picocolors";
7
+ import * as R28 from "ramda";
7
8
 
8
9
  // src/colors/colorMetadata.ts
9
10
  import * as R from "ramda";
@@ -392,7 +393,7 @@ var cssClassRename = (dictionary) => ({
392
393
  var cssVarRename = (dictionary) => ({
393
394
  postcssPlugin: `Replaces CSS variables ${hash(dictionary)}`,
394
395
  Declaration(decl) {
395
- const { value, prop: prop4 } = decl;
396
+ const { value, prop: prop3 } = decl;
396
397
  const deleted = /* @__PURE__ */ new Set();
397
398
  for (const [from, to] of Object.entries(dictionary)) {
398
399
  if (R4.isNotEmpty(to)) {
@@ -403,8 +404,8 @@ var cssVarRename = (dictionary) => ({
403
404
  decl.value = value.replace(from, to);
404
405
  continue;
405
406
  }
406
- if (R4.includes(from, prop4) && decl.variable) {
407
- decl.prop = prop4.replace(from, to);
407
+ if (R4.includes(from, prop3) && decl.variable) {
408
+ decl.prop = prop3.replace(from, to);
408
409
  }
409
410
  }
410
411
  }
@@ -415,58 +416,133 @@ var cssVarRename = (dictionary) => ({
415
416
  });
416
417
 
417
418
  // src/migrations/codemods/css/run.ts
418
- import fs2 from "fs";
419
419
  import glob from "fast-glob";
420
420
  import postcss from "postcss";
421
421
 
422
- // src/utils.ts
422
+ // src/utils/filesystem.ts
423
423
  import fs from "fs/promises";
424
+ import path from "path";
424
425
  import pc2 from "picocolors";
425
- var mkdir = async (dir, dry) => {
426
- if (dry) {
427
- console.log(`${pc2.blue("mkdir")} ${dir}`);
428
- return Promise.resolve();
429
- }
430
- const exists = await fs.access(dir, fs.constants.F_OK).then(() => true).catch(() => false);
431
- if (exists) {
432
- return Promise.resolve();
433
- }
434
- return fs.mkdir(dir, { recursive: true });
435
- };
436
- var writeFile = async (path6, data, dry) => {
437
- if (dry) {
438
- console.log(`${pc2.blue("writeFile")} ${path6}`);
439
- return Promise.resolve();
440
- }
441
- return fs.writeFile(path6, data, { encoding: "utf-8" }).catch((error) => {
442
- console.error(pc2.red(`Error writing file: ${path6}`));
443
- console.error(pc2.red(error));
444
- throw error;
445
- });
446
- };
447
- var cleanDir = async (dir, dry) => {
448
- if (dry) {
449
- console.log(`${pc2.blue("cleanDir")} ${dir}`);
450
- return Promise.resolve();
426
+ var FileSystem = class {
427
+ isInitialized = false;
428
+ dry = false;
429
+ verbose = false;
430
+ /** Default working directory is where the process was started */
431
+ workingDir = process.cwd();
432
+ outDir = this.workingDir;
433
+ /** Initialize the file system */
434
+ init({ dry, outdir, verbose }) {
435
+ if (this.isInitialized) {
436
+ console.warn(pc2.yellow("FileSystem is already initialized. Ignoring subsequent init call."));
437
+ return;
438
+ }
439
+ if (dry) {
440
+ console.log(pc2.blue("Initializing FileSystem in dry-run mode. No files will be written."));
441
+ }
442
+ this.dry = dry ?? false;
443
+ this.verbose = verbose ?? false;
444
+ this.outDir = outdir ? path.isAbsolute(outdir) ? outdir : path.join(this.workingDir, outdir) : this.workingDir;
445
+ if (this.verbose) {
446
+ console.log(
447
+ `FileSystem initialized with workingDir: ${pc2.green(this.workingDir)}, outDir: ${pc2.green(this.outDir)}`
448
+ );
449
+ }
450
+ this.isInitialized = true;
451
451
  }
452
- console.log(`
452
+ /**
453
+ * Creates a directory if it does not already exist.
454
+ *
455
+ * @param dir - The path of the directory to create.
456
+ *
457
+ * @returns A promise that resolves when the operation is complete.
458
+ * If the directory already exists or `dry` is `true`, the promise resolves immediately.
459
+ */
460
+ mkdir = async (dir) => {
461
+ if (this.dry) {
462
+ console.log(`${pc2.blue("mkdir")} ${dir}`);
463
+ return Promise.resolve();
464
+ }
465
+ const exists = await fs.access(dir, fs.constants.F_OK).then(() => true).catch(() => false);
466
+ if (exists) {
467
+ return Promise.resolve();
468
+ }
469
+ return fs.mkdir(dir, { recursive: true });
470
+ };
471
+ writeFile = async (path5, data) => {
472
+ if (this.dry) {
473
+ console.log(`${pc2.blue("writeFile")} ${path5}`);
474
+ return Promise.resolve();
475
+ }
476
+ return fs.writeFile(path5, data, { encoding: "utf-8" }).catch((error) => {
477
+ console.error(pc2.red(`Error writing file: ${path5}`));
478
+ console.error(pc2.red(error));
479
+ throw error;
480
+ });
481
+ };
482
+ cp = async (src, dest, filter) => {
483
+ if (this.dry) {
484
+ console.log(`${pc2.blue("cp")} ${src} ${dest}`);
485
+ return Promise.resolve();
486
+ }
487
+ return fs.cp(src, dest, { recursive: true, filter });
488
+ };
489
+ copyFile = async (src, dest) => {
490
+ if (this.dry) {
491
+ console.log(`${pc2.blue("copyFile")} ${src} to ${dest}`);
492
+ return Promise.resolve();
493
+ }
494
+ return fs.copyFile(src, dest);
495
+ };
496
+ cleanDir = async (dir) => {
497
+ if (this.dry) {
498
+ console.log(`${pc2.blue("cleanDir")} ${dir}`);
499
+ return Promise.resolve();
500
+ }
501
+ console.log(`
453
502
  \u{1F525} Cleaning dir ${pc2.red(`${dir.trim()}`)} `);
454
- return fs.rm(dir, { recursive: true, force: true });
455
- };
456
- var readFile = async (path6, dry, allowFileNotFound) => {
457
- if (dry) {
458
- console.log(`${pc2.blue("readFile")} ${path6}`);
459
- return Promise.resolve("");
460
- }
461
- try {
462
- return await fs.readFile(path6, "utf-8");
463
- } catch (error) {
464
- if (allowFileNotFound && error.code === "ENOENT") {
465
- return "";
503
+ return fs.rm(dir, { recursive: true, force: true });
504
+ };
505
+ readFile = async (path5, allowFileNotFound) => {
506
+ if (this.dry) {
507
+ console.log(`${pc2.blue("readFile")} ${path5}`);
466
508
  }
467
- throw error;
468
- }
509
+ try {
510
+ return await fs.readFile(path5, "utf-8");
511
+ } catch (error) {
512
+ if (allowFileNotFound && error.code === "ENOENT") {
513
+ return "";
514
+ }
515
+ throw error;
516
+ }
517
+ };
518
+ readdir = async (path5) => {
519
+ if (this.dry) {
520
+ console.log(`${pc2.blue("readdir")} ${path5}`);
521
+ }
522
+ try {
523
+ return await fs.readdir(path5);
524
+ } catch (error) {
525
+ if (error.code === "ENOENT") {
526
+ return [];
527
+ }
528
+ throw error;
529
+ }
530
+ };
531
+ writeFiles = async (files, outDir, log) => {
532
+ for (const { destination: filename, output } of files) {
533
+ if (filename) {
534
+ const filePath = path.join(outDir, filename);
535
+ const fileDir = path.dirname(filePath);
536
+ if (log) {
537
+ console.log(filename);
538
+ }
539
+ await this.mkdir(fileDir);
540
+ await this.writeFile(filePath, output);
541
+ }
542
+ }
543
+ };
469
544
  };
545
+ var dsfs = new FileSystem();
470
546
 
471
547
  // src/migrations/codemods/css/run.ts
472
548
  var runCssCodemod = async ({ plugins = [], globPattern = "./**/*.css" }) => {
@@ -482,9 +558,9 @@ var runCssCodemod = async ({ plugins = [], globPattern = "./**/*.css" }) => {
482
558
  if (file.includes("node_modules") || file.includes("dist")) {
483
559
  return;
484
560
  }
485
- const contents = readFile(file).toString();
486
- const result = await processor.process(contents, { from: file });
487
- fs2.writeFileSync(file, result.css);
561
+ const contents = await dsfs.readFile(file);
562
+ const result = await processor.process(contents.toString(), { from: file });
563
+ await dsfs.writeFile(file, result.css);
488
564
  });
489
565
  await Promise.all(filePromises);
490
566
  };
@@ -874,7 +950,6 @@ var migrations_default = {
874
950
  };
875
951
 
876
952
  // src/tokens/build.ts
877
- import path from "path";
878
953
  import pc7 from "picocolors";
879
954
  import * as R22 from "ramda";
880
955
 
@@ -884,11 +959,11 @@ import pc5 from "picocolors";
884
959
  // package.json
885
960
  var package_default = {
886
961
  name: "@digdir/designsystemet",
887
- version: "1.12.1",
962
+ version: "1.13.1",
888
963
  description: "CLI for Designsystemet",
889
964
  author: "Designsystemet team",
890
965
  engines: {
891
- node: ">=20 <25"
966
+ node: ">=20.20.1"
892
967
  },
893
968
  repository: {
894
969
  type: "git",
@@ -952,16 +1027,16 @@ var package_default = {
952
1027
  hsluv: "^1.0.1",
953
1028
  "object-hash": "^3.0.0",
954
1029
  picocolors: "^1.1.1",
955
- postcss: "^8.5.6",
1030
+ postcss: "^8.5.8",
956
1031
  ramda: "^0.32.0",
957
- "style-dictionary": "^5.3.0",
1032
+ "style-dictionary": "^5.3.3",
958
1033
  zod: "^4.3.6",
959
1034
  "zod-validation-error": "^5.0.0"
960
1035
  },
961
1036
  devDependencies: {
962
1037
  "@tokens-studio/types": "0.5.2",
963
1038
  "@types/chroma-js": "^3.1.2",
964
- "@types/node": "^24.10.13",
1039
+ "@types/node": "^24.12.0",
965
1040
  "@types/object-hash": "^3.0.6",
966
1041
  "@types/ramda": "^0.31.1",
967
1042
  tsup: "^8.5.1",
@@ -1007,8 +1082,8 @@ var pathStartsWithOneOf = R6.curry(
1007
1082
  }
1008
1083
  const tokenPath = mapToLowerCase(token.path);
1009
1084
  const matchPathsStartingWith = R6.map((pathOrString) => {
1010
- const path6 = typeof pathOrString === "string" ? [pathOrString] : pathOrString;
1011
- return R6.startsWith(mapToLowerCase(path6), tokenPath);
1085
+ const path5 = typeof pathOrString === "string" ? [pathOrString] : pathOrString;
1086
+ return R6.startsWith(mapToLowerCase(path5), tokenPath);
1012
1087
  }, paths);
1013
1088
  return hasAnyTruth(matchPathsStartingWith);
1014
1089
  }
@@ -1033,11 +1108,11 @@ function isColorCategoryToken(token, category) {
1033
1108
  var isDigit = (s) => /^\d+$/.test(s);
1034
1109
  function traverseObj(obj, fn) {
1035
1110
  for (const key in obj) {
1036
- const prop4 = obj[key];
1037
- if (prop4 != null) {
1038
- fn.apply(null, [obj, key, prop4]);
1039
- if (typeof prop4 === "object") {
1040
- traverseObj(prop4, fn);
1111
+ const prop3 = obj[key];
1112
+ if (prop3 != null) {
1113
+ fn.apply(null, [obj, key, prop3]);
1114
+ if (typeof prop3 === "object") {
1115
+ traverseObj(prop3, fn);
1041
1116
  }
1042
1117
  }
1043
1118
  }
@@ -2449,8 +2524,8 @@ ${dynamicColors}`;
2449
2524
  import pc6 from "picocolors";
2450
2525
  import * as R21 from "ramda";
2451
2526
  var defaultFileHeader2 = `build: v${package_default.version}`;
2452
- var getFileNameWithoutExtension = (path6) => {
2453
- const pathSegments = path6.split("/");
2527
+ var getFileNameWithoutExtension = (path5) => {
2528
+ const pathSegments = path5.split("/");
2454
2529
  return pathSegments[pathSegments.length - 1].split(".").slice(0, -1).join(".");
2455
2530
  };
2456
2531
  var createThemeCSSFiles = ({
@@ -2530,25 +2605,13 @@ ${fileHeader}
2530
2605
  };
2531
2606
 
2532
2607
  // src/tokens/build.ts
2533
- async function write(files, outDir, dry) {
2534
- for (const { destination, output } of files) {
2535
- if (destination) {
2536
- const filePath = path.join(outDir, destination);
2537
- const fileDir = path.dirname(filePath);
2538
- console.log(destination);
2539
- await mkdir(fileDir, dry);
2540
- await writeFile(filePath, output, dry);
2541
- }
2542
- }
2543
- }
2544
2608
  var buildTokens = async (options) => {
2545
- const outDir = path.resolve(options.outDir);
2546
- const tokensDir = path.resolve(options.tokensDir);
2547
- const $themes = JSON.parse(await readFile(`${tokensDir}/$themes.json`));
2609
+ const tokensDir = options.tokensDir;
2610
+ const $themes = JSON.parse(await dsfs.readFile(`${tokensDir}/$themes.json`));
2548
2611
  const processed$themes = $themes.map(processThemeObject);
2549
2612
  let $designsystemet;
2550
2613
  try {
2551
- const $designsystemetContent = await readFile(`${tokensDir}/$designsystemet.jsonc`);
2614
+ const $designsystemetContent = await dsfs.readFile(`${tokensDir}/$designsystemet.jsonc`);
2552
2615
  $designsystemet = JSON.parse($designsystemetContent);
2553
2616
  } catch (_error) {
2554
2617
  }
@@ -2556,7 +2619,6 @@ var buildTokens = async (options) => {
2556
2619
  \u{1F3D7}\uFE0F Start building tokens in ${pc7.green(tokensDir)}`);
2557
2620
  const processedBuilds = await processPlatform({
2558
2621
  ...options,
2559
- outDir,
2560
2622
  tokensDir,
2561
2623
  type: "build",
2562
2624
  processed$themes,
@@ -2575,19 +2637,9 @@ design-tokens: v${$designsystemet.version}` : ""
2575
2637
  const tailwindFiles = createTailwindCSSFiles(cssFiles);
2576
2638
  files = files.concat(tailwindFiles.filter(Boolean));
2577
2639
  }
2578
- console.log(`
2579
- \u{1F4BE} Writing build to ${pc7.green(outDir)}`);
2580
- await write(files, outDir, options.dry);
2581
- console.log(`
2582
- \u2705 Finished building tokens!`);
2583
- return processedBuilds;
2640
+ return files;
2584
2641
  };
2585
2642
 
2586
- // src/tokens/create/write.ts
2587
- import path2 from "path";
2588
- import pc8 from "picocolors";
2589
- import * as R23 from "ramda";
2590
-
2591
2643
  // src/tokens/create/generators/$designsystemet.ts
2592
2644
  function generate$Designsystemet() {
2593
2645
  return {
@@ -2783,56 +2835,36 @@ function generateTypographyGroup(themes) {
2783
2835
  ];
2784
2836
  }
2785
2837
 
2786
- // src/tokens/create/write.ts
2838
+ // src/tokens/create/files.ts
2787
2839
  var stringify = (data) => JSON.stringify(data, null, 2);
2788
- var writeTokens = async (options) => {
2840
+ var createTokenFiles = async (options) => {
2789
2841
  const {
2790
2842
  outDir,
2791
2843
  tokenSets,
2792
- theme: { name: themeName, colors: colors2 },
2793
- dry
2844
+ theme: { colors: colors2 },
2845
+ themeNames
2794
2846
  } = options;
2795
- const targetDir = path2.resolve(process.cwd(), String(outDir));
2796
- const $themesPath = path2.join(targetDir, "$themes.json");
2797
- const $metadataPath = path2.join(targetDir, "$metadata.json");
2798
- const $designsystemetPath = path2.join(targetDir, "$designsystemet.jsonc");
2799
- let themeObjects = [];
2847
+ const $themesPath = "$themes.json";
2848
+ const $metadataPath = "$metadata.json";
2849
+ const $designsystemetPath = "$designsystemet.jsonc";
2800
2850
  const sizeModes2 = ["small", "medium", "large"];
2801
- await mkdir(targetDir, dry);
2802
- try {
2803
- const $themes2 = await readFile($themesPath);
2804
- if ($themes2) {
2805
- themeObjects = JSON.parse($themes2);
2806
- }
2807
- } catch (_error) {
2808
- }
2809
- const concatThemeNames = R23.pipe(
2810
- R23.filter((obj) => R23.toLower(obj.group || "") === "theme"),
2811
- R23.map(R23.prop("name")),
2812
- // New theme is added to the end of the list so we keep the same order from config and Token Studio
2813
- R23.append(themeName),
2814
- R23.uniq
2815
- );
2816
- const themes = concatThemeNames(themeObjects);
2817
- console.log(`
2818
- Themes: ${pc8.blue(themes.join(", "))}`);
2819
- const $themes = await generate$Themes(["dark", "light"], themes, colors2, sizeModes2);
2820
- const $metadata = generate$Metadata(["dark", "light"], themes, colors2, sizeModes2);
2851
+ await dsfs.mkdir(outDir);
2852
+ const $themes = await generate$Themes(["dark", "light"], themeNames, colors2, sizeModes2);
2853
+ const $metadata = generate$Metadata(["dark", "light"], themeNames, colors2, sizeModes2);
2821
2854
  const $designsystemet = generate$Designsystemet();
2822
- await writeFile($themesPath, stringify($themes), dry);
2823
- await writeFile($metadataPath, stringify($metadata), dry);
2824
- await writeFile($designsystemetPath, stringify($designsystemet), dry);
2855
+ const files = [];
2856
+ files.push({ destination: $themesPath, output: stringify($themes) });
2857
+ files.push({ destination: $metadataPath, output: stringify($metadata) });
2858
+ files.push({ destination: $designsystemetPath, output: stringify($designsystemet) });
2825
2859
  for (const [set4, tokens] of tokenSets) {
2826
- const fileDir = path2.join(targetDir, path2.dirname(set4));
2827
- await mkdir(fileDir, dry);
2828
- const filePath = path2.join(targetDir, `${set4}.json`);
2829
- await writeFile(filePath, stringify(tokens), dry);
2860
+ const filePath = `${set4}.json`;
2861
+ files.push({ destination: filePath, output: stringify(tokens) });
2830
2862
  }
2831
- console.log(`Finished creating Designsystem design tokens in ${pc8.green(outDir)} for theme ${pc8.blue(themeName)}`);
2863
+ return files;
2832
2864
  };
2833
2865
 
2834
2866
  // src/tokens/create/generators/primitives/color-scheme.ts
2835
- import * as R24 from "ramda";
2867
+ import * as R23 from "ramda";
2836
2868
  var generateColor = (colorArray, overrides) => {
2837
2869
  const obj = {};
2838
2870
  const $type = "color";
@@ -2869,11 +2901,11 @@ var generateColorScheme = (themeName, colorScheme2, colors2, overrides) => {
2869
2901
  });
2870
2902
  return Object.keys(positionOverrides).length > 0 ? positionOverrides : void 0;
2871
2903
  };
2872
- const main = R24.mapObjIndexed(
2904
+ const main = R23.mapObjIndexed(
2873
2905
  (color, colorName) => generateColor(generateColorScale(color, colorScheme2), createColorOverrides(colorName)),
2874
2906
  colors2.main
2875
2907
  );
2876
- const support = R24.mapObjIndexed(
2908
+ const support = R23.mapObjIndexed(
2877
2909
  (color, colorName) => generateColor(generateColorScale(color, colorScheme2), createColorOverrides(colorName)),
2878
2910
  colors2.support
2879
2911
  );
@@ -2883,7 +2915,7 @@ var generateColorScheme = (themeName, colorScheme2, colors2, overrides) => {
2883
2915
  ...baseColors,
2884
2916
  ...overrides?.severity
2885
2917
  };
2886
- const globalColors = R24.mapObjIndexed(
2918
+ const globalColors = R23.mapObjIndexed(
2887
2919
  (color, colorName) => generateColor(generateColorScale(color, colorScheme2), createColorOverrides(colorName)),
2888
2920
  baseColorsWithOverrides
2889
2921
  );
@@ -3435,7 +3467,7 @@ var fontSizes = {
3435
3467
  };
3436
3468
 
3437
3469
  // src/tokens/create/generators/semantic/color.ts
3438
- import * as R25 from "ramda";
3470
+ import * as R24 from "ramda";
3439
3471
  var generateSemanticColors = (colors2, _themeName) => {
3440
3472
  const mainColorNames = Object.keys(colors2.main);
3441
3473
  const supportColorNames = Object.keys(colors2.support);
@@ -3474,7 +3506,7 @@ var baseColorTemplate = {
3474
3506
  };
3475
3507
  var generateColorScaleTokens = (colorName) => {
3476
3508
  const colorScale = {};
3477
- for (const [colorSemantic, colorNumber] of R25.toPairs(semanticColorMap)) {
3509
+ for (const [colorSemantic, colorNumber] of R24.toPairs(semanticColorMap)) {
3478
3510
  colorScale[colorSemantic] = {
3479
3511
  $type: "color",
3480
3512
  $value: `{color.${colorName}.${colorNumber}}`
@@ -3902,7 +3934,7 @@ function generateSemanticStyle() {
3902
3934
  }
3903
3935
 
3904
3936
  // src/tokens/create/generators/themes/theme.ts
3905
- import * as R26 from "ramda";
3937
+ import * as R25 from "ramda";
3906
3938
  var generateTheme = (colors2, themeName, borderRadius) => {
3907
3939
  const mainColorNames = Object.keys(colors2.main);
3908
3940
  const supportColorNames = Object.keys(colors2.support);
@@ -3934,8 +3966,8 @@ var generateTheme = (colors2, themeName, borderRadius) => {
3934
3966
  },
3935
3967
  ...remainingThemeFile
3936
3968
  };
3937
- const baseBorderRadius = R26.lensPath(["border-radius", "base", "$value"]);
3938
- const updatedThemeFile = R26.set(baseBorderRadius, String(borderRadius), themeFile);
3969
+ const baseBorderRadius = R25.lensPath(["border-radius", "base", "$value"]);
3970
+ const updatedThemeFile = R25.set(baseBorderRadius, String(borderRadius), themeFile);
3939
3971
  const token = JSON.parse(
3940
3972
  JSON.stringify(
3941
3973
  updatedThemeFile,
@@ -4007,7 +4039,7 @@ var generateBase = (themeName) => ({
4007
4039
  });
4008
4040
  var generateColorScaleTokens3 = (colorName, themeName) => {
4009
4041
  const colorScale = {};
4010
- for (const [_, colorNumber] of R26.toPairs(semanticColorMap)) {
4042
+ for (const [_, colorNumber] of R25.toPairs(semanticColorMap)) {
4011
4043
  colorScale[colorNumber] = {
4012
4044
  $type: "color",
4013
4045
  $value: `{${themeName}.${colorName}.${colorNumber}}`
@@ -4062,12 +4094,11 @@ var createTokens = async (theme) => {
4062
4094
  };
4063
4095
 
4064
4096
  // src/tokens/generate-config.ts
4065
- import fs3 from "fs/promises";
4066
- import path3 from "path";
4067
- import pc9 from "picocolors";
4097
+ import path2 from "path";
4098
+ import pc8 from "picocolors";
4068
4099
  async function readJsonFile(filePath) {
4069
4100
  try {
4070
- const content = await fs3.readFile(filePath, "utf-8");
4101
+ const content = await dsfs.readFile(filePath);
4071
4102
  return JSON.parse(content);
4072
4103
  } catch (err) {
4073
4104
  throw new Error(`Failed to read token file at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -4083,21 +4114,21 @@ function extractBaseColor(colorScale) {
4083
4114
  return null;
4084
4115
  }
4085
4116
  async function discoverThemes(tokensDir) {
4086
- const lightModePath = path3.join(tokensDir, "themes");
4117
+ const lightModePath = path2.join(tokensDir, "themes");
4087
4118
  try {
4088
- const files = await fs3.readdir(lightModePath);
4119
+ const files = await dsfs.readdir(lightModePath);
4089
4120
  const themes = files.filter((file) => file.endsWith(".json")).map((file) => file.replace(".json", ""));
4090
4121
  return themes;
4091
4122
  } catch {
4092
- throw new Error(`Could not find themes. Make sure ${pc9.blue(lightModePath)} exists and contains theme JSON files.`);
4123
+ throw new Error(`Could not find themes. Make sure ${pc8.blue(lightModePath)} exists and contains theme JSON files.`);
4093
4124
  }
4094
4125
  }
4095
4126
  async function readThemeTokens(tokensDir, themeName) {
4096
- const themePath = path3.join(tokensDir, "primitives", "modes", "color-scheme", "light", `${themeName}.json`);
4127
+ const themePath = path2.join(tokensDir, "primitives", "modes", "color-scheme", "light", `${themeName}.json`);
4097
4128
  return readJsonFile(themePath);
4098
4129
  }
4099
4130
  async function readThemeConfig(tokensDir, themeName) {
4100
- const themeConfigPath = path3.join(tokensDir, "themes", `${themeName}.json`);
4131
+ const themeConfigPath = path2.join(tokensDir, "themes", `${themeName}.json`);
4101
4132
  try {
4102
4133
  return await readJsonFile(themeConfigPath);
4103
4134
  } catch {
@@ -4131,7 +4162,7 @@ function extractFontFamily(themeConfig) {
4131
4162
  return void 0;
4132
4163
  }
4133
4164
  async function readTypographyConfig(tokensDir, themeName) {
4134
- const typographyConfigPath = path3.join(
4165
+ const typographyConfigPath = path2.join(
4135
4166
  tokensDir,
4136
4167
  "primitives",
4137
4168
  "modes",
@@ -4191,33 +4222,33 @@ function categorizeColors(themeTokens, themeName) {
4191
4222
  return { main, support, neutral };
4192
4223
  }
4193
4224
  async function generateConfigFromTokens(options) {
4194
- const { tokensDir, dry = false } = options;
4225
+ const { tokensDir } = options;
4195
4226
  console.log(`
4196
- Reading tokens from ${pc9.blue(tokensDir)}`);
4227
+ Reading tokens from ${pc8.blue(tokensDir)}`);
4197
4228
  const themes = await discoverThemes(tokensDir);
4198
4229
  if (themes.length === 0) {
4199
4230
  throw new Error(`
4200
- No themes found in ${pc9.blue(tokensDir)}`);
4231
+ No themes found in ${pc8.blue(tokensDir)}`);
4201
4232
  }
4202
4233
  console.log(`
4203
- Found ${pc9.green(String(themes.length))} theme(s): ${themes.map((t) => pc9.cyan(t)).join(", ")}`);
4234
+ Found ${pc8.green(String(themes.length))} theme(s): ${themes.map((t) => pc8.cyan(t)).join(", ")}`);
4204
4235
  const config = {
4205
4236
  outDir: tokensDir,
4206
4237
  themes: {}
4207
4238
  };
4208
4239
  for (const themeName of themes) {
4209
4240
  console.log(`
4210
- Processing theme ${pc9.cyan(themeName)}...`);
4241
+ Processing theme ${pc8.cyan(themeName)}...`);
4211
4242
  const themeTokens = await readThemeTokens(tokensDir, themeName);
4212
4243
  const themeConfig = await readThemeConfig(tokensDir, themeName);
4213
4244
  const typographyConfig = await readTypographyConfig(tokensDir, themeName);
4214
4245
  const { main, support, neutral } = categorizeColors(themeTokens, themeName);
4215
4246
  if (Object.keys(main).length === 0) {
4216
- console.warn(pc9.yellow(`
4247
+ console.warn(pc8.yellow(`
4217
4248
  Warning: No main colors found for theme ${themeName}`));
4218
4249
  }
4219
4250
  if (!neutral) {
4220
- console.warn(pc9.yellow(`
4251
+ console.warn(pc8.yellow(`
4221
4252
  Warning: No neutral color found for theme ${themeName}`));
4222
4253
  continue;
4223
4254
  }
@@ -4234,46 +4265,38 @@ Warning: No neutral color found for theme ${themeName}`));
4234
4265
  };
4235
4266
  console.log(
4236
4267
  `
4237
- \u2705 Main colors: ${Object.keys(main).map((c) => pc9.cyan(c)).join(", ") || pc9.dim("none")}`
4268
+ \u2705 Main colors: ${Object.keys(main).map((c) => pc8.cyan(c)).join(", ") || pc8.dim("none")}`
4238
4269
  );
4239
4270
  console.log(
4240
4271
  `
4241
- \u2705 Support colors: ${Object.keys(support).map((c) => pc9.cyan(c)).join(", ") || pc9.dim("none")}`
4272
+ \u2705 Support colors: ${Object.keys(support).map((c) => pc8.cyan(c)).join(", ") || pc8.dim("none")}`
4242
4273
  );
4243
4274
  console.log(`
4244
- \u2705 Neutral: ${pc9.cyan(neutral)}`);
4275
+ \u2705 Neutral: ${pc8.cyan(neutral)}`);
4245
4276
  if (borderRadius !== void 0) {
4246
4277
  console.log(`
4247
- \u2705 Border radius: ${pc9.cyan(String(borderRadius))}`);
4278
+ \u2705 Border radius: ${pc8.cyan(String(borderRadius))}`);
4248
4279
  }
4249
4280
  if (fontFamily) {
4250
4281
  console.log(`
4251
- \u2705 Font family: ${pc9.cyan(fontFamily)}`);
4282
+ \u2705 Font family: ${pc8.cyan(fontFamily)}`);
4252
4283
  }
4253
4284
  }
4254
- if (!dry && options.outFile) {
4255
- const configJson = JSON.stringify(config, null, 2);
4256
- await fs3.writeFile(options.outFile, configJson, "utf-8");
4257
- console.log();
4258
- console.log(`
4259
- \u2705 Config file written to ${pc9.blue(options.outFile)}`);
4260
- }
4261
4285
  return config;
4262
4286
  }
4263
4287
 
4264
4288
  // bin/config.ts
4265
- import path5 from "path";
4266
- import pc11 from "picocolors";
4267
- import * as R28 from "ramda";
4268
-
4269
- // src/config.ts
4270
4289
  import pc10 from "picocolors";
4271
4290
  import * as R27 from "ramda";
4291
+
4292
+ // src/config.ts
4293
+ import pc9 from "picocolors";
4294
+ import * as R26 from "ramda";
4272
4295
  import { z } from "zod";
4273
4296
  import { fromError } from "zod-validation-error";
4274
- function mapPathToOptionName(path6) {
4275
- const normalisedPath = path6[0] === "themes" ? ["theme", ...R27.drop(2, path6)] : path6;
4276
- const option = R27.path(normalisedPath, cliOptions);
4297
+ function mapPathToOptionName(path5) {
4298
+ const normalisedPath = path5[0] === "themes" ? ["theme", ...R26.drop(2, path5)] : path5;
4299
+ const option = R26.path(normalisedPath, cliOptions);
4277
4300
  if (typeof option !== "string") {
4278
4301
  return;
4279
4302
  }
@@ -4287,33 +4310,33 @@ function makeFriendlyError(err) {
4287
4310
  const optionName = mapPathToOptionName(issue.path);
4288
4311
  const errorCode = `(error code: ${issue.code})`;
4289
4312
  const optionMessage = optionName ? ` or CLI option --${optionName}` : "";
4290
- return ` - Error in JSON value ${pc10.red(issuePath)}${optionMessage}:
4291
- ${issue.message} ${pc10.dim(errorCode)}`;
4313
+ return ` - Error in JSON value ${pc9.red(issuePath)}${optionMessage}:
4314
+ ${issue.message} ${pc9.dim(errorCode)}`;
4292
4315
  }).join("\n")
4293
4316
  });
4294
4317
  } catch (_err2) {
4295
- console.error(pc10.red(err instanceof Error ? err.message : "Unknown error occurred while parsing config file"));
4318
+ console.error(pc9.red(err instanceof Error ? err.message : "Unknown error occurred while parsing config file"));
4296
4319
  console.error(err instanceof Error ? err.stack : "No stack trace available");
4297
4320
  }
4298
4321
  }
4299
- function validateConfig(schema, unvalidatedConfig, configPath) {
4322
+ function validateConfig(schema, unvalidatedConfig, configFilePath) {
4300
4323
  try {
4301
4324
  return schema.parse(unvalidatedConfig);
4302
4325
  } catch (err) {
4303
- console.error(pc10.redBright(`Invalid config file at ${pc10.red(configPath)}`));
4326
+ console.error(pc9.redBright(`Invalid config file at ${pc9.red(configFilePath)}`));
4304
4327
  const validationError = makeFriendlyError(err);
4305
4328
  console.error(validationError?.toString());
4306
4329
  process.exit(1);
4307
4330
  }
4308
4331
  }
4309
- function parseConfig(configFile, configPath) {
4332
+ function parseConfig(configFile, configFilePath) {
4310
4333
  if (!configFile) {
4311
4334
  return {};
4312
4335
  }
4313
4336
  try {
4314
4337
  return JSON.parse(configFile);
4315
4338
  } catch (err) {
4316
- console.error(pc10.redBright(`Failed parsing config file at ${pc10.red(configPath)}`));
4339
+ console.error(pc9.redBright(`Failed parsing config file at ${pc9.red(configFilePath)}`));
4317
4340
  const validationError = makeFriendlyError(err);
4318
4341
  console.error(validationError?.toString());
4319
4342
  process.exit(1);
@@ -4404,32 +4427,31 @@ var getDefaultCliOption = getOptionIfMatchingSource("default");
4404
4427
  var getCliOption = getOptionIfMatchingSource("cli", "default");
4405
4428
 
4406
4429
  // bin/config.ts
4407
- async function readConfigFile(configPath, allowFileNotFound = true) {
4408
- const resolvedPath = path5.resolve(process.cwd(), configPath);
4430
+ async function readConfigFile(configFilePath, allowFileNotFound = true) {
4409
4431
  let configFile;
4410
4432
  try {
4411
- configFile = await readFile(resolvedPath, false, allowFileNotFound);
4433
+ configFile = await dsfs.readFile(configFilePath, allowFileNotFound);
4412
4434
  } catch (err) {
4413
4435
  if (allowFileNotFound) {
4414
4436
  return "";
4415
4437
  }
4416
- console.error(pc11.redBright(`Could not read config file at ${pc11.blue(resolvedPath)}`));
4438
+ console.error(pc10.redBright(`Could not read config file at ${pc10.blue(configFilePath)}`));
4417
4439
  throw err;
4418
4440
  }
4419
4441
  if (configFile) {
4420
- console.log(`Found config file: ${pc11.green(resolvedPath)}`);
4442
+ console.log(`Found config file: ${pc10.green(configFilePath)}`);
4421
4443
  }
4422
4444
  return configFile;
4423
4445
  }
4424
4446
  async function parseCreateConfig(configFile, options) {
4425
- const { cmd, theme = "theme", configPath } = options;
4426
- const configParsed = parseConfig(configFile, configPath);
4447
+ const { cmd, theme = "theme", configFilePath } = options;
4448
+ const configParsed = parseConfig(configFile, configFilePath);
4427
4449
  const themeColors = Object.values(configParsed?.themes ?? {}).map(
4428
- (x) => /* @__PURE__ */ new Set([...R28.keys(x.colors.main), ...R28.keys(x.colors.support)])
4450
+ (x) => /* @__PURE__ */ new Set([...R27.keys(x.colors.main), ...R27.keys(x.colors.support)])
4429
4451
  );
4430
- if (!R28.all(R28.equals(R28.__, themeColors[0]), themeColors)) {
4431
- console.error(pc11.redBright(`In config, all themes must have the same custom color names, but we found:`));
4432
- const themeNames = R28.keys(configParsed.themes ?? {});
4452
+ if (!R27.all(R27.equals(R27.__, themeColors[0]), themeColors)) {
4453
+ console.error(pc10.redBright(`In config, all themes must have the same custom color names, but we found:`));
4454
+ const themeNames = R27.keys(configParsed.themes ?? {});
4433
4455
  themeColors.forEach((colors2, index) => {
4434
4456
  const colorNames2 = Array.from(colors2);
4435
4457
  console.log(` - ${themeNames[index]}: ${colorNames2.join(", ")}`);
@@ -4437,7 +4459,7 @@ async function parseCreateConfig(configFile, options) {
4437
4459
  console.log();
4438
4460
  process.exit(1);
4439
4461
  }
4440
- const noUndefined = R28.reject(R28.isNil);
4462
+ const noUndefined = R27.reject(R27.isNil);
4441
4463
  const getThemeOptions = (optionGetter) => noUndefined({
4442
4464
  colors: noUndefined({
4443
4465
  main: optionGetter(cmd, "mainColors"),
@@ -4453,10 +4475,10 @@ async function parseCreateConfig(configFile, options) {
4453
4475
  const unvalidatedConfig = noUndefined({
4454
4476
  outDir: configParsed?.outDir ?? getCliOption(cmd, "outDir"),
4455
4477
  clean: configParsed?.clean ?? getCliOption(cmd, "clean"),
4456
- themes: configParsed?.themes ? R28.map((jsonThemeValues) => {
4478
+ themes: configParsed?.themes ? R27.map((jsonThemeValues) => {
4457
4479
  const defaultThemeValues = getThemeOptions(getDefaultCliOption);
4458
4480
  const cliThemeValues = getThemeOptions(getSuppliedCliOption);
4459
- const mergedConfigs = R28.mergeDeepRight(defaultThemeValues, R28.mergeDeepRight(jsonThemeValues, cliThemeValues));
4481
+ const mergedConfigs = R27.mergeDeepRight(defaultThemeValues, R27.mergeDeepRight(jsonThemeValues, cliThemeValues));
4460
4482
  return mergedConfigs;
4461
4483
  }, configParsed.themes) : (
4462
4484
  // If there are no themes specified in the JSON config, we use both explicit
@@ -4466,11 +4488,7 @@ async function parseCreateConfig(configFile, options) {
4466
4488
  }
4467
4489
  )
4468
4490
  });
4469
- return validateConfig(configFileCreateSchema, unvalidatedConfig, configPath);
4470
- }
4471
- async function parseBuildConfig(configFile, { configPath }) {
4472
- const configParsed = parseConfig(configFile, configPath);
4473
- return validateConfig(commonConfig, configParsed, configPath);
4491
+ return validateConfig(configFileCreateSchema, unvalidatedConfig, configFilePath);
4474
4492
  }
4475
4493
 
4476
4494
  // bin/designsystemet.ts
@@ -4489,81 +4507,104 @@ var DEFAULT_TOKENS_CREATE_DIR = "./design-tokens";
4489
4507
  var DEFAULT_TOKENS_BUILD_DIR = "./design-tokens-build";
4490
4508
  var DEFAULT_FONT = "Inter";
4491
4509
  var DEFAULT_THEME_NAME = "theme";
4492
- var DEFAULT_CONFIG_FILE = "designsystemet.config.json";
4510
+ var DEFAULT_CONFIG_FILEPATH = "designsystemet.config.json";
4493
4511
  function makeTokenCommands() {
4494
4512
  const tokenCmd = createCommand("tokens");
4495
- tokenCmd.command("build").description("Build Designsystemet tokens").option("-t, --tokens <string>", `Path to ${pc12.blue("design-tokens")}`, DEFAULT_TOKENS_CREATE_DIR).option(
4513
+ tokenCmd.command("build").description("Build Designsystemet tokens").option("-t, --tokens <string>", `Path to ${pc11.blue("design-tokens")}`, DEFAULT_TOKENS_CREATE_DIR).option(
4496
4514
  "-o, --out-dir <string>",
4497
- `Output directory for built ${pc12.blue("design-tokens")}`,
4515
+ `Output directory for built ${pc11.blue("design-tokens")}`,
4498
4516
  DEFAULT_TOKENS_BUILD_DIR
4499
- ).option(`--${cliOptions.clean} [boolean]`, "Clean output directory before building tokens", parseBoolean, false).option("--dry [boolean]", `Dry run for built ${pc12.blue("design-tokens")}`, parseBoolean, false).option("--verbose", "Enable verbose output", false).option("--config <string>", `Path to config file (default: "${DEFAULT_CONFIG_FILE}")`).option("--experimental-tailwind", "Generate Tailwind CSS classes for tokens", false).action(async (opts) => {
4517
+ ).option(`--${cliOptions.clean} [boolean]`, "Clean output directory before building tokens", parseBoolean, false).option("--dry [boolean]", `Dry run for built ${pc11.blue("design-tokens")}`, parseBoolean, false).option("--verbose", "Enable verbose output", false).option("--config <string>", `Path to config file (default: "${DEFAULT_CONFIG_FILEPATH}")`).option("--experimental-tailwind", "Generate Tailwind CSS classes for tokens", false).action(async (opts) => {
4500
4518
  console.log(figletAscii);
4501
- const { verbose, clean, dry, experimentalTailwind } = opts;
4502
- const tokensDir = typeof opts.tokens === "string" ? opts.tokens : DEFAULT_TOKENS_CREATE_DIR;
4503
- const outDir = typeof opts.outDir === "string" ? opts.outDir : "./dist/tokens";
4504
- const { configFile, configPath } = await getConfigFile(opts.config);
4505
- const config = await parseBuildConfig(configFile, { configPath });
4506
- if (dry) {
4507
- console.log(`Performing dry run, no files will be written`);
4508
- }
4519
+ const { verbose, clean, dry, experimentalTailwind, tokens } = opts;
4520
+ dsfs.init({ dry, outdir: opts.outDir, verbose });
4521
+ const outDir = dsfs.outDir;
4509
4522
  if (clean) {
4510
- await cleanDir(outDir, dry);
4523
+ await dsfs.cleanDir(outDir);
4511
4524
  }
4512
- await buildTokens({ tokensDir, outDir, verbose, dry, tailwind: experimentalTailwind, ...config });
4525
+ const files = await buildTokens({
4526
+ tokensDir: tokens,
4527
+ verbose,
4528
+ tailwind: experimentalTailwind
4529
+ });
4530
+ console.log(`
4531
+ \u{1F4BE} Writing build to ${pc11.green(outDir)}`);
4532
+ await dsfs.writeFiles(files, outDir, true);
4533
+ console.log(`
4534
+ \u2705 Finished building tokens in ${pc11.green(outDir)}`);
4513
4535
  return Promise.resolve();
4514
4536
  });
4515
4537
  tokenCmd.command("create").description("Create Designsystemet tokens").option(`-m, --${cliOptions.theme.colors.main} <name:hex...>`, `Main colors`, parseColorValues).option(`-s, --${cliOptions.theme.colors.support} <name:hex...>`, `Support colors`, parseColorValues).option(`-n, --${cliOptions.theme.colors.neutral} <hex>`, `Neutral hex color`, convertToHex).option(
4516
4538
  `-o, --${cliOptions.outDir} <string>`,
4517
- `Output directory for created ${pc12.blue("design-tokens")}`,
4539
+ `Output directory for created ${pc11.blue("design-tokens")}`,
4518
4540
  DEFAULT_TOKENS_CREATE_DIR
4519
- ).option(`--${cliOptions.clean} [boolean]`, "Clean output directory before creating tokens", parseBoolean, false).option("--dry [boolean]", `Dry run for created ${pc12.blue("design-tokens")}`, parseBoolean, false).option(`-f, --${cliOptions.theme.typography.fontFamily} <string>`, `Font family (experimental)`, DEFAULT_FONT).option(
4541
+ ).option(`--${cliOptions.clean} [boolean]`, "Clean output directory before creating tokens", parseBoolean, false).option("--dry [boolean]", `Dry run for created ${pc11.blue("design-tokens")}`, parseBoolean, false).option(`-f, --${cliOptions.theme.typography.fontFamily} <string>`, `Font family (experimental)`, DEFAULT_FONT).option(
4520
4542
  `-b, --${cliOptions.theme.borderRadius} <number>`,
4521
4543
  `Unitless base border-radius in px`,
4522
4544
  (radiusAsString) => Number(radiusAsString),
4523
4545
  4
4524
- ).option("--theme <string>", "Theme name (ignored when using JSON config file)", DEFAULT_THEME_NAME).option("--config <string>", `Path to config file (default: "${DEFAULT_CONFIG_FILE}")`).action(async (opts, cmd) => {
4546
+ ).option("--theme <string>", "Theme name (ignored when using JSON config file)", DEFAULT_THEME_NAME).option("--config <string>", `Path to config file (default: "${DEFAULT_CONFIG_FILEPATH}")`).action(async (opts, cmd) => {
4525
4547
  console.log(figletAscii);
4526
4548
  if (opts.dry) {
4527
4549
  console.log(`Performing dry run, no files will be written`);
4528
4550
  }
4529
- const { configFile, configPath } = await getConfigFile(opts.config);
4551
+ const themeName = opts.theme;
4552
+ const { configFile, configFilePath } = await getConfigFile(opts.config);
4530
4553
  const config = await parseCreateConfig(configFile, {
4531
- theme: opts.theme,
4554
+ theme: themeName,
4532
4555
  cmd,
4533
- configPath
4556
+ configFilePath
4534
4557
  });
4558
+ const themeNames = Object.keys(config.themes);
4559
+ if (themeNames.length > 0) {
4560
+ console.log(`Using themes from config file: ${pc11.blue(themeNames.join(", "))}`);
4561
+ }
4562
+ dsfs.init({ dry: opts.dry, outdir: config.outDir });
4563
+ const outDir = dsfs.outDir;
4535
4564
  if (config.clean) {
4536
- await cleanDir(config.outDir, opts.dry);
4565
+ await dsfs.cleanDir(outDir);
4537
4566
  }
4567
+ let files = [];
4538
4568
  if (config.themes) {
4539
4569
  for (const [name, themeWithoutName] of Object.entries(config.themes)) {
4540
4570
  const theme = { name, ...themeWithoutName };
4541
4571
  const { tokenSets } = await createTokens(theme);
4542
- await writeTokens({ outDir: config.outDir, theme, dry: opts.dry, tokenSets });
4572
+ files = files.concat(await createTokenFiles({ outDir, theme, tokenSets, themeNames }));
4543
4573
  }
4544
4574
  }
4575
+ await dsfs.writeFiles(files, outDir);
4576
+ console.log(`
4577
+ \u2705 Finished creating tokens in ${pc11.green(outDir)} for themes: ${pc11.blue(themeNames.join(", "))}`);
4578
+ return Promise.resolve();
4545
4579
  });
4546
4580
  return tokenCmd;
4547
4581
  }
4548
4582
  program.addCommand(makeTokenCommands());
4549
- program.command("generate-config-from-tokens").description("Generate a config file from existing design tokens. Will not include overrides.").option("-d, --dir <string>", "Path to design tokens directory", DEFAULT_TOKENS_CREATE_DIR).option("-o, --out <string>", "Output path for config file", DEFAULT_CONFIG_FILE).option("--dry [boolean]", "Dry run - show config without writing file", parseBoolean, false).action(async (opts) => {
4583
+ program.command("generate-config-from-tokens").description("Generate a config file from existing design tokens. Will not include overrides.").option("-d, --dir <string>", "Path to design tokens directory", DEFAULT_TOKENS_CREATE_DIR).option("-o, --out <string>", "Output path for config file", DEFAULT_CONFIG_FILEPATH).option("--dry [boolean]", "Dry run - show config without writing file", parseBoolean, false).action(async (opts) => {
4550
4584
  console.log(figletAscii);
4551
4585
  const { dry } = opts;
4552
- const tokensDir = typeof opts.dir === "string" ? opts.dir : DEFAULT_TOKENS_CREATE_DIR;
4553
- const outFile = typeof opts.out === "string" ? opts.out : DEFAULT_CONFIG_FILE;
4586
+ const tokensDir = path4.resolve(opts.dir);
4587
+ const configFilePath = path4.resolve(opts.out);
4588
+ dsfs.init({ dry, outdir: path4.dirname(configFilePath) });
4554
4589
  try {
4555
4590
  const config = await generateConfigFromTokens({
4556
4591
  tokensDir,
4557
- outFile: dry ? void 0 : outFile,
4558
- dry
4592
+ outFile: configFilePath
4559
4593
  });
4560
4594
  if (dry) {
4561
4595
  console.log();
4562
4596
  console.log("Generated config (dry run):");
4563
4597
  console.log(JSON.stringify(config, null, 2));
4564
4598
  }
4599
+ if (configFilePath) {
4600
+ const configJson = JSON.stringify(config, null, 2);
4601
+ await dsfs.writeFile(configFilePath, configJson);
4602
+ console.log();
4603
+ console.log(`
4604
+ \u2705 Config file written to ${pc11.blue(configFilePath)}`);
4605
+ }
4565
4606
  } catch (error) {
4566
- console.error(pc12.redBright("Error generating config:"));
4607
+ console.error(pc11.redBright("Error generating config:"));
4567
4608
  console.error(error instanceof Error ? error.message : String(error));
4568
4609
  process.exit(1);
4569
4610
  }
@@ -4581,8 +4622,8 @@ program.command("migrate").description("run a Designsystemet migration").addArgu
4581
4622
  console.error("Migration not found!");
4582
4623
  throw "Aborting";
4583
4624
  }
4584
- console.log(`Applying migration ${pc12.blue(migrationKey)} with glob: ${pc12.green(glob2)}`);
4585
- migration?.(glob2).then(() => console.log(`Migration ${pc12.blue(migrationKey)} finished`)).catch((error) => console.log(error));
4625
+ console.log(`Applying migration ${pc11.blue(migrationKey)} with glob: ${pc11.green(glob2)}`);
4626
+ migration?.(glob2).then(() => console.log(`Migration ${pc11.blue(migrationKey)} finished`)).catch((error) => console.log(error));
4586
4627
  } else {
4587
4628
  console.log("Migrate: please specify a migration name or --list");
4588
4629
  }
@@ -4596,11 +4637,11 @@ function parseColorValues(value, previous = {}) {
4596
4637
  function parseBoolean(value) {
4597
4638
  return value === "true" || value === true;
4598
4639
  }
4599
- async function getConfigFile(config) {
4600
- const allowFileNotFound = R29.isNil(config) || config === DEFAULT_CONFIG_FILE;
4601
- const configPath = config ?? DEFAULT_CONFIG_FILE;
4602
- const configFile = await readConfigFile(configPath, allowFileNotFound);
4603
- return { configFile, configPath };
4640
+ async function getConfigFile(userConfigFilePath) {
4641
+ const allowFileNotFound = R28.isNil(userConfigFilePath) || userConfigFilePath === DEFAULT_CONFIG_FILEPATH;
4642
+ const configFilePath = userConfigFilePath ?? DEFAULT_CONFIG_FILEPATH;
4643
+ const configFile = await readConfigFile(configFilePath, allowFileNotFound);
4644
+ return { configFile, configFilePath };
4604
4645
  }
4605
4646
  export {
4606
4647
  figletAscii