@digdir/designsystemet 0.1.0-alpha.18 → 0.1.0-alpha.19

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 (91) hide show
  1. package/LICENSE +7 -0
  2. package/dist/bin/designsystemet.js +24 -28
  3. package/dist/src/colors/colorUtils.js +223 -315
  4. package/dist/src/colors/index.js +3 -3
  5. package/dist/src/colors/themeUtils.js +227 -319
  6. package/dist/src/colors/types.js +0 -1
  7. package/dist/src/init/createTokensPackage.js +223 -203
  8. package/dist/src/init/generateMetadataJson.js +19 -14
  9. package/dist/src/init/generateThemesJson.js +49 -40
  10. package/dist/src/init/index.js +7 -4
  11. package/dist/src/init/nextStepsMarkdown.js +15 -13
  12. package/dist/src/init/template/prettier.config.js +5 -7
  13. package/dist/src/init/template/template-files/package.json +1 -0
  14. package/dist/src/init/utils.js +11 -7
  15. package/dist/src/migrations/beta-to-v1.js +342 -339
  16. package/dist/src/migrations/codemods/css/plugins.js +40 -36
  17. package/dist/src/migrations/codemods/css/run.js +15 -20
  18. package/dist/src/migrations/codemods/jsx/classname-prefix.js +57 -63
  19. package/dist/src/migrations/codemods/jsx/run.js +17 -19
  20. package/dist/src/migrations/index.js +6 -3
  21. package/dist/src/migrations/react-beta-to-v1.js +4 -3
  22. package/dist/src/tokens/actions.js +25 -23
  23. package/dist/src/tokens/build.js +65 -51
  24. package/dist/src/tokens/configs.js +188 -223
  25. package/dist/src/tokens/formats/css.js +143 -150
  26. package/dist/src/tokens/formats/js-tokens.js +27 -26
  27. package/dist/src/tokens/transformers.js +39 -41
  28. package/dist/src/tokens/utils/noCase.js +25 -25
  29. package/dist/src/tokens/utils/permutateThemes.js +50 -64
  30. package/dist/src/tokens/utils/utils.js +12 -25
  31. package/package.json +8 -3
  32. package/dist/src/test/a.css +0 -39
  33. package/dist/src/test/jsx-test.js +0 -12
  34. package/dist/types/bin/designsystemet.d.ts +0 -3
  35. package/dist/types/bin/designsystemet.d.ts.map +0 -1
  36. package/dist/types/src/colors/colorUtils.d.ts +0 -126
  37. package/dist/types/src/colors/colorUtils.d.ts.map +0 -1
  38. package/dist/types/src/colors/index.d.ts +0 -4
  39. package/dist/types/src/colors/index.d.ts.map +0 -1
  40. package/dist/types/src/colors/themeUtils.d.ts +0 -102
  41. package/dist/types/src/colors/themeUtils.d.ts.map +0 -1
  42. package/dist/types/src/colors/types.d.ts +0 -16
  43. package/dist/types/src/colors/types.d.ts.map +0 -1
  44. package/dist/types/src/init/createTokensPackage.d.ts +0 -5
  45. package/dist/types/src/init/createTokensPackage.d.ts.map +0 -1
  46. package/dist/types/src/init/generateMetadataJson.d.ts +0 -6
  47. package/dist/types/src/init/generateMetadataJson.d.ts.map +0 -1
  48. package/dist/types/src/init/generateThemesJson.d.ts +0 -3
  49. package/dist/types/src/init/generateThemesJson.d.ts.map +0 -1
  50. package/dist/types/src/init/index.d.ts +0 -3
  51. package/dist/types/src/init/index.d.ts.map +0 -1
  52. package/dist/types/src/init/nextStepsMarkdown.d.ts +0 -3
  53. package/dist/types/src/init/nextStepsMarkdown.d.ts.map +0 -1
  54. package/dist/types/src/init/template/prettier.config.d.mts +0 -9
  55. package/dist/types/src/init/template/prettier.config.d.mts.map +0 -1
  56. package/dist/types/src/init/utils.d.ts +0 -4
  57. package/dist/types/src/init/utils.d.ts.map +0 -1
  58. package/dist/types/src/migrations/beta-to-v1.d.ts +0 -3
  59. package/dist/types/src/migrations/beta-to-v1.d.ts.map +0 -1
  60. package/dist/types/src/migrations/codemods/css/plugins.d.ts +0 -6
  61. package/dist/types/src/migrations/codemods/css/plugins.d.ts.map +0 -1
  62. package/dist/types/src/migrations/codemods/css/run.d.ts +0 -8
  63. package/dist/types/src/migrations/codemods/css/run.d.ts.map +0 -1
  64. package/dist/types/src/migrations/codemods/jsx/classname-prefix.d.ts +0 -10
  65. package/dist/types/src/migrations/codemods/jsx/classname-prefix.d.ts.map +0 -1
  66. package/dist/types/src/migrations/codemods/jsx/run.d.ts +0 -7
  67. package/dist/types/src/migrations/codemods/jsx/run.d.ts.map +0 -1
  68. package/dist/types/src/migrations/index.d.ts +0 -6
  69. package/dist/types/src/migrations/index.d.ts.map +0 -1
  70. package/dist/types/src/migrations/react-beta-to-v1.d.ts +0 -3
  71. package/dist/types/src/migrations/react-beta-to-v1.d.ts.map +0 -1
  72. package/dist/types/src/test/jsx-test.d.ts +0 -4
  73. package/dist/types/src/test/jsx-test.d.ts.map +0 -1
  74. package/dist/types/src/tokens/actions.d.ts +0 -6
  75. package/dist/types/src/tokens/actions.d.ts.map +0 -1
  76. package/dist/types/src/tokens/build.d.ts +0 -11
  77. package/dist/types/src/tokens/build.d.ts.map +0 -1
  78. package/dist/types/src/tokens/configs.d.ts +0 -31
  79. package/dist/types/src/tokens/configs.d.ts.map +0 -1
  80. package/dist/types/src/tokens/formats/css.d.ts +0 -5
  81. package/dist/types/src/tokens/formats/css.d.ts.map +0 -1
  82. package/dist/types/src/tokens/formats/js-tokens.d.ts +0 -6
  83. package/dist/types/src/tokens/formats/js-tokens.d.ts.map +0 -1
  84. package/dist/types/src/tokens/transformers.d.ts +0 -5
  85. package/dist/types/src/tokens/transformers.d.ts.map +0 -1
  86. package/dist/types/src/tokens/utils/noCase.d.ts +0 -11
  87. package/dist/types/src/tokens/utils/noCase.d.ts.map +0 -1
  88. package/dist/types/src/tokens/utils/permutateThemes.d.ts +0 -17
  89. package/dist/types/src/tokens/utils/permutateThemes.d.ts.map +0 -1
  90. package/dist/types/src/tokens/utils/utils.d.ts +0 -24
  91. package/dist/types/src/tokens/utils/utils.d.ts.map +0 -1
@@ -2,229 +2,249 @@ import path from "node:path";
2
2
  import fs from "node:fs/promises";
3
3
  import chalk from "chalk";
4
4
  import prompts from "prompts";
5
- import packageJsonTemplate from "./template/template-files/package.json" with {
6
- type: 'json'
7
- };
5
+ import packageJsonTemplate from "./template/template-files/package.json" with { type: "json" };
8
6
  import generateMetadata from "./generateMetadataJson.js";
9
7
  import generateThemes from "./generateThemesJson.js";
10
8
  import { toGeneratedCssFileName, normalizeTokenSetName, toValidPackageName } from "./utils.js";
11
9
  import { nextStepsMarkdown } from "./nextStepsMarkdown.js";
12
- const MODES = [
13
- 'Light',
14
- 'Dark',
15
- 'Contrast'
16
- ];
10
+ const MODES = ["Light", "Dark", "Contrast"];
17
11
  const promptOptions = {
18
- onCancel: ()=>{
19
- console.log(`${chalk.red('✖')} Operation cancelled`);
20
- process.exit();
21
- }
12
+ onCancel: () => {
13
+ console.log(`${chalk.red("\u2716")} Operation cancelled`);
14
+ process.exit();
15
+ }
22
16
  };
23
- export async function createTokensPackage(targetDir) {
24
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
25
- const DIRNAME = import.meta.dirname || __dirname;
26
- const DEFAULT_FILES_PATH = path.join(DIRNAME, './template/default-files');
27
- const TOKEN_TEMPLATE_FILES_PATH = path.join(DIRNAME, './template/template-files/design-tokens');
28
- const TARGET_DIR = path.resolve(process.cwd(), targetDir);
29
- const initialPackageName = toValidPackageName(path.basename(TARGET_DIR));
30
- // Check target directory contents
31
- let isTargetDirEmpty = true;
32
- try {
33
- const files = await fs.readdir(TARGET_DIR);
34
- isTargetDirEmpty = files.length === 0;
35
- } catch (err) {
36
- if (err.code === 'ENOENT') {
37
- // Directory doesn't exist, so we're good
38
- } else {
39
- console.error(err);
40
- console.log('Continuing...');
41
- }
17
+ async function createTokensPackage(targetDir) {
18
+ const DIRNAME = import.meta.dirname || __dirname;
19
+ const DEFAULT_FILES_PATH = path.join(DIRNAME, "./template/default-files");
20
+ const TOKEN_TEMPLATE_FILES_PATH = path.join(DIRNAME, "./template/template-files/design-tokens");
21
+ const TARGET_DIR = path.resolve(process.cwd(), targetDir);
22
+ const initialPackageName = toValidPackageName(path.basename(TARGET_DIR));
23
+ let isTargetDirEmpty = true;
24
+ try {
25
+ const files = await fs.readdir(TARGET_DIR);
26
+ isTargetDirEmpty = files.length === 0;
27
+ } catch (err) {
28
+ if (err.code === "ENOENT") {
29
+ } else {
30
+ console.error(err);
31
+ console.log("Continuing...");
42
32
  }
43
- const { directoryAction } = await prompts({
44
- name: 'directoryAction',
45
- type: isTargetDirEmpty ? null : 'select',
46
- message: 'Target directory is not empty. How should we proceed?',
47
- choices: [
48
- {
49
- title: 'Clean',
50
- value: 'clean',
51
- description: 'Empty the directory and continue'
52
- },
53
- {
54
- title: 'Ignore',
55
- value: 'ignore',
56
- description: 'Keep directory as is. Files may be overwritten with new output.'
57
- },
58
- {
59
- title: 'Exit',
60
- value: 'exit',
61
- description: 'Exit without doing anything.'
62
- }
63
- ]
64
- }, promptOptions);
65
- if (directoryAction === 'exit') {
66
- process.exit();
67
- }
68
- const { packageName } = await prompts([
33
+ }
34
+ const { directoryAction } = await prompts(
35
+ {
36
+ name: "directoryAction",
37
+ type: isTargetDirEmpty ? null : "select",
38
+ message: "Target directory is not empty. How should we proceed?",
39
+ choices: [
69
40
  {
70
- name: 'packageName',
71
- type: 'text',
72
- message: 'Enter a package name (for package.json)',
73
- initial: initialPackageName
74
- }
75
- ], promptOptions);
76
- const { modes, themeCount, tokensDir } = await prompts([
41
+ title: "Clean",
42
+ value: "clean",
43
+ description: "Empty the directory and continue"
44
+ },
77
45
  {
78
- name: 'themeCount',
79
- type: 'number',
80
- message: 'How many themes do you want?',
81
- initial: 1,
82
- min: 1
46
+ title: "Ignore",
47
+ value: "ignore",
48
+ description: "Keep directory as is. Files may be overwritten with new output."
83
49
  },
84
50
  {
85
- name: 'modes',
86
- type: 'multiselect',
87
- choices: MODES.filter((x)=>x !== 'Light').map((mode)=>({
88
- title: mode,
89
- value: mode
90
- })),
91
- message: 'Which color modes do you want?',
92
- instructions: `
51
+ title: "Exit",
52
+ value: "exit",
53
+ description: "Exit without doing anything."
54
+ }
55
+ ]
56
+ },
57
+ promptOptions
58
+ );
59
+ if (directoryAction === "exit") {
60
+ process.exit();
61
+ }
62
+ const { packageName } = await prompts(
63
+ [
64
+ {
65
+ name: "packageName",
66
+ type: "text",
67
+ message: "Enter a package name (for package.json)",
68
+ initial: initialPackageName
69
+ }
70
+ ],
71
+ promptOptions
72
+ );
73
+ const { modes, themeCount, tokensDir } = await prompts(
74
+ [
75
+ {
76
+ name: "themeCount",
77
+ type: "number",
78
+ message: "How many themes do you want?",
79
+ initial: 1,
80
+ min: 1
81
+ },
82
+ {
83
+ name: "modes",
84
+ type: "multiselect",
85
+ choices: MODES.filter((x) => x !== "Light").map((mode) => ({
86
+ title: mode,
87
+ value: mode
88
+ })),
89
+ message: "Which color modes do you want?",
90
+ instructions: `
93
91
  Instructions:
94
- ↑/↓: Highlight option
95
- ←/→/[space]: Toggle selection
92
+ \u2191/\u2193: Highlight option
93
+ \u2190/\u2192/[space]: Toggle selection
96
94
  a: Toggle all
97
95
  enter/return: Complete answer
98
- ${chalk.green('◉')} Light ${chalk.dim('- This is the default mode, and cannot be disabled')}`,
99
- onState: (obj)=>{
100
- obj.value.unshift({
101
- title: 'Light',
102
- value: 'Light',
103
- selected: true
104
- });
105
- }
106
- },
96
+ ${chalk.green("\u25C9")} Light ${chalk.dim("- This is the default mode, and cannot be disabled")}`,
97
+ onState: (obj) => {
98
+ obj.value.unshift({ title: "Light", value: "Light", selected: true });
99
+ }
100
+ },
101
+ {
102
+ name: "tokensDir",
103
+ type: "text",
104
+ initial: "design-tokens",
105
+ message: `Enter the desired path for the design tokens`
106
+ }
107
+ ],
108
+ promptOptions
109
+ );
110
+ const themes = [];
111
+ const TOKENS_TARGET_DIR = path.join(TARGET_DIR, tokensDir);
112
+ for (let n = 1; n <= themeCount; n++) {
113
+ const theme = await prompts(
114
+ [
107
115
  {
108
- name: 'tokensDir',
109
- type: 'text',
110
- initial: 'design-tokens',
111
- message: `Enter the desired path for the design tokens`
116
+ name: "name",
117
+ type: "text",
118
+ message: `Enter the name of the ${ordinal(n)} theme`,
119
+ validate: (value) => isValidThemeName(themes, value)
112
120
  }
113
- ], promptOptions);
114
- const themes = [];
115
- const TOKENS_TARGET_DIR = path.join(TARGET_DIR, tokensDir);
116
- for(let n = 1; n <= themeCount; n++){
117
- const theme = await prompts([
118
- {
119
- name: 'name',
120
- type: 'text',
121
- message: `Enter the name of the ${ordinal(n)} theme`,
122
- validate: (value)=>isValidThemeName(themes, value)
123
- }
124
- ], promptOptions);
125
- themes.push(theme.name);
126
- }
127
- const { defaultTheme = themes[0] } = await prompts({
128
- name: 'defaultTheme',
129
- type: themeCount === 1 ? null : 'select',
130
- message: 'Select the default theme to export in package.json',
131
- choices: themes.map((theme)=>({
132
- title: theme,
133
- value: theme
134
- })),
135
- initial: 0
136
- }, promptOptions);
137
- console.log(`
121
+ ],
122
+ promptOptions
123
+ );
124
+ themes.push(theme.name);
125
+ }
126
+ const { defaultTheme = themes[0] } = await prompts(
127
+ {
128
+ name: "defaultTheme",
129
+ type: themeCount === 1 ? null : "select",
130
+ message: "Select the default theme to export in package.json",
131
+ choices: themes.map((theme) => ({ title: theme, value: theme })),
132
+ initial: 0
133
+ },
134
+ promptOptions
135
+ );
136
+ console.log(
137
+ `
138
138
  Will now create the following:
139
- ${chalk.bold('Package name')}: ${packageName}
140
- ${chalk.bold('Directory')}: ${TARGET_DIR}
141
- ${chalk.bold('Tokens directory')}: ${TOKENS_TARGET_DIR}
142
- ${chalk.bold('Themes')}: ${themes.join(', ')}
143
- ${chalk.bold('Default theme')}: ${defaultTheme}
144
- ${chalk.bold('Color modes')}: ${modes.join(', ')}
145
- `);
146
- if (directoryAction === 'clean') {
147
- console.log(chalk.bold.red(`Warning: Contents of ${TARGET_DIR} will be deleted`));
148
- }
149
- if (directoryAction === 'ignore') {
150
- console.log(chalk.bold.yellow(`Warning: Existing files in ${TARGET_DIR} may be overwritten`));
139
+ ${chalk.bold("Package name")}: ${packageName}
140
+ ${chalk.bold("Directory")}: ${TARGET_DIR}
141
+ ${chalk.bold("Tokens directory")}: ${TOKENS_TARGET_DIR}
142
+ ${chalk.bold("Themes")}: ${themes.join(", ")}
143
+ ${chalk.bold("Default theme")}: ${defaultTheme}
144
+ ${chalk.bold("Color modes")}: ${modes.join(", ")}
145
+ `
146
+ );
147
+ if (directoryAction === "clean") {
148
+ console.log(chalk.bold.red(`Warning: Contents of ${TARGET_DIR} will be deleted`));
149
+ }
150
+ if (directoryAction === "ignore") {
151
+ console.log(chalk.bold.yellow(`Warning: Existing files in ${TARGET_DIR} may be overwritten`));
152
+ }
153
+ const res = await prompts(
154
+ {
155
+ name: "proceed",
156
+ type: "confirm",
157
+ message: "Proceed?",
158
+ initial: directoryAction === void 0
159
+ // default to proceeding if the output directory is empty
160
+ },
161
+ promptOptions
162
+ );
163
+ if (!res.proceed) {
164
+ process.exit();
165
+ }
166
+ if (directoryAction === "clean") {
167
+ await fs.rm(TARGET_DIR, { recursive: true });
168
+ }
169
+ await fs.cp(DEFAULT_FILES_PATH, path.join(TARGET_DIR), {
170
+ recursive: true
171
+ });
172
+ if (tokensDir !== "design-tokens") {
173
+ await fs.rename(path.join(TARGET_DIR, "design-tokens"), path.join(TOKENS_TARGET_DIR));
174
+ }
175
+ try {
176
+ await fs.mkdir(path.join(TOKENS_TARGET_DIR, "themes"));
177
+ } catch {
178
+ }
179
+ for (const theme of themes.map(normalizeTokenSetName)) {
180
+ for (const mode of modes.map(normalizeTokenSetName)) {
181
+ await fs.cp(
182
+ path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/global.json`),
183
+ path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/global.json`),
184
+ { recursive: true }
185
+ );
186
+ const template2 = await fs.readFile(
187
+ path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/theme-template.json`)
188
+ );
189
+ await fs.writeFile(
190
+ path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/${theme}.json`),
191
+ template2.toString("utf-8").replaceAll("<theme>", theme)
192
+ );
151
193
  }
152
- const res = await prompts({
153
- name: 'proceed',
154
- type: 'confirm',
155
- message: 'Proceed?',
156
- initial: directoryAction === undefined
157
- }, promptOptions);
158
- if (!res.proceed) {
159
- process.exit();
160
- }
161
- if (directoryAction === 'clean') {
162
- await fs.rm(TARGET_DIR, {
163
- recursive: true
164
- });
165
- }
166
- await fs.cp(DEFAULT_FILES_PATH, path.join(TARGET_DIR), {
167
- recursive: true
168
- });
169
- if (tokensDir !== 'design-tokens') {
170
- await fs.rename(path.join(TARGET_DIR, 'design-tokens'), path.join(TOKENS_TARGET_DIR));
171
- }
172
- try {
173
- await fs.mkdir(path.join(TOKENS_TARGET_DIR, 'themes'));
174
- } catch {
175
- // Directory creation failed, probably because the directory already exists
176
- }
177
- for (const theme of themes.map(normalizeTokenSetName)){
178
- for (const mode of modes.map(normalizeTokenSetName)){
179
- // Copy the global file for the color mode
180
- await fs.cp(path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/global.json`), path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/global.json`), {
181
- recursive: true
182
- });
183
- // Create theme primitives for the color mode
184
- const template = await fs.readFile(path.join(TOKEN_TEMPLATE_FILES_PATH, `primitives/colors/${mode}/theme-template.json`));
185
- await fs.writeFile(path.join(TOKENS_TARGET_DIR, `primitives/colors/${mode}/${theme}.json`), template.toString('utf-8').replaceAll('<theme>', theme));
186
- }
187
- // Create main theme token set
188
- const template = await fs.readFile(path.join(TOKEN_TEMPLATE_FILES_PATH, `themes/theme-template.json`));
189
- await fs.writeFile(path.join(TOKENS_TARGET_DIR, `themes/${theme}.json`), template.toString('utf-8').replaceAll('<theme>', theme));
190
- await fs.writeFile(path.join(TOKENS_TARGET_DIR, '$metadata.json'), JSON.stringify(generateMetadata(modes, themes), undefined, 2));
191
- await fs.writeFile(path.join(TOKENS_TARGET_DIR, '$themes.json'), JSON.stringify(generateThemes(modes, themes), undefined, 2));
192
- }
193
- // Configure package.json file
194
- packageJsonTemplate.name = packageName;
195
- packageJsonTemplate.main = packageJsonTemplate.main.replace('<default-theme>', toGeneratedCssFileName(defaultTheme));
196
- await fs.writeFile(path.join(TARGET_DIR, 'package.json'), JSON.stringify(packageJsonTemplate, undefined, 2));
197
- const readmePath = path.join(TARGET_DIR, 'README.md');
198
- const currentReadme = await fs.readFile(readmePath);
199
- await fs.writeFile(readmePath, [
200
- currentReadme.toString('utf-8'),
201
- nextStepsMarkdown(themes, modes, tokensDir, packageName)
202
- ].join('\n'));
203
- console.log('🎉 Files successfully generated!');
204
- console.log(`Read about the next steps in the generated README at ${readmePath}`);
194
+ const template = await fs.readFile(path.join(TOKEN_TEMPLATE_FILES_PATH, `themes/theme-template.json`));
195
+ await fs.writeFile(
196
+ path.join(TOKENS_TARGET_DIR, `themes/${theme}.json`),
197
+ template.toString("utf-8").replaceAll("<theme>", theme)
198
+ );
199
+ await fs.writeFile(
200
+ path.join(TOKENS_TARGET_DIR, "$metadata.json"),
201
+ JSON.stringify(generateMetadata(modes, themes), void 0, 2)
202
+ );
203
+ await fs.writeFile(
204
+ path.join(TOKENS_TARGET_DIR, "$themes.json"),
205
+ JSON.stringify(generateThemes(modes, themes), void 0, 2)
206
+ );
207
+ }
208
+ packageJsonTemplate.name = packageName;
209
+ packageJsonTemplate.main = packageJsonTemplate.main.replaceAll(
210
+ "<default-theme>",
211
+ toGeneratedCssFileName(defaultTheme)
212
+ );
213
+ await fs.writeFile(path.join(TARGET_DIR, "package.json"), JSON.stringify(packageJsonTemplate, void 0, 2));
214
+ const readmePath = path.join(TARGET_DIR, "README.md");
215
+ const currentReadme = await fs.readFile(readmePath);
216
+ await fs.writeFile(
217
+ readmePath,
218
+ [currentReadme.toString("utf-8"), nextStepsMarkdown(themes, modes, tokensDir, packageName)].join("\n")
219
+ );
220
+ console.log("\u{1F389} Files successfully generated!");
221
+ console.log(`Read about the next steps in the generated README at ${readmePath}`);
205
222
  }
206
223
  function isValidThemeName(themes, value) {
207
- const s = value.trim();
208
- if (s.length === 0) {
209
- return 'Theme name cannot be empty.';
210
- }
211
- if (themes.includes(s)) {
212
- return 'Theme names must be unique.';
213
- }
214
- if (/[^a-zæøå0-9 _-]/i.test(s)) {
215
- return 'Theme name can only contain letters, numbers, dashes and underscores.';
216
- }
217
- return true;
224
+ const s = value.trim();
225
+ if (s.length === 0) {
226
+ return "Theme name cannot be empty.";
227
+ }
228
+ if (themes.includes(s)) {
229
+ return "Theme names must be unique.";
230
+ }
231
+ if (/[^a-zæøå0-9 _-]/i.test(s)) {
232
+ return "Theme name can only contain letters, numbers, dashes and underscores.";
233
+ }
234
+ return true;
218
235
  }
219
236
  function ordinal(n) {
220
- switch(n){
221
- case 1:
222
- return '1st';
223
- case 2:
224
- return '2nd';
225
- case 3:
226
- return '3rd';
227
- default:
228
- return `${n}th`;
229
- }
237
+ switch (n) {
238
+ case 1:
239
+ return "1st";
240
+ case 2:
241
+ return "2nd";
242
+ case 3:
243
+ return "3rd";
244
+ default:
245
+ return `${n}th`;
246
+ }
230
247
  }
248
+ export {
249
+ createTokensPackage
250
+ };
@@ -1,16 +1,21 @@
1
1
  import { normalizeTokenSetName } from "./utils.js";
2
- export default function generateMetadataJson(modes, themes) {
3
- return {
4
- tokenSetOrder: [
5
- 'primitives/globals',
6
- 'primitives/typography/default',
7
- ...modes.flatMap((mode)=>[
8
- `primitives/colors/${normalizeTokenSetName(mode)}/global`,
9
- ...themes.map((theme)=>`primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}`)
10
- ]),
11
- ...themes.map((theme)=>`themes/${normalizeTokenSetName(theme)}`),
12
- 'semantic/color',
13
- 'semantic/style'
14
- ]
15
- };
2
+ function generateMetadataJson(modes, themes) {
3
+ return {
4
+ tokenSetOrder: [
5
+ "primitives/globals",
6
+ "primitives/typography/default",
7
+ ...modes.flatMap((mode) => [
8
+ `primitives/colors/${normalizeTokenSetName(mode)}/global`,
9
+ ...themes.map(
10
+ (theme) => `primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}`
11
+ )
12
+ ]),
13
+ ...themes.map((theme) => `themes/${normalizeTokenSetName(theme)}`),
14
+ "semantic/color",
15
+ "semantic/style"
16
+ ]
17
+ };
16
18
  }
19
+ export {
20
+ generateMetadataJson as default
21
+ };
@@ -1,50 +1,59 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { TokenSetStatus } from "@tokens-studio/types";
3
3
  import { normalizeTokenSetName } from "./utils.js";
4
- export default function generateThemesJson(modes, themes) {
5
- return [
6
- ...generateModesGroup(modes, themes),
7
- ...generateThemesGroup(themes),
8
- generateSemanticGroup()
9
- ];
4
+ function generateThemesJson(modes, themes) {
5
+ return [
6
+ ...generateModesGroup(modes, themes),
7
+ ...generateThemesGroup(themes),
8
+ generateSemanticGroup()
9
+ ];
10
10
  }
11
11
  function generateModesGroup(modes, themes) {
12
- return modes.map((mode)=>({
13
- id: randomUUID(),
14
- name: mode,
15
- selectedTokenSets: Object.fromEntries([
16
- [
17
- `primitives/colors/${normalizeTokenSetName(mode)}/global`,
18
- TokenSetStatus.ENABLED
19
- ],
20
- ...themes.map((theme)=>[
21
- `primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}`,
22
- TokenSetStatus.ENABLED
23
- ])
24
- ]),
25
- group: 'Mode'
26
- }));
12
+ return modes.map(
13
+ (mode) => ({
14
+ id: randomUUID(),
15
+ name: mode,
16
+ selectedTokenSets: Object.fromEntries([
17
+ [
18
+ `primitives/colors/${normalizeTokenSetName(mode)}/global`,
19
+ TokenSetStatus.ENABLED
20
+ ],
21
+ ...themes.map(
22
+ (theme) => [
23
+ `primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}`,
24
+ TokenSetStatus.ENABLED
25
+ ]
26
+ )
27
+ ]),
28
+ group: "Mode"
29
+ })
30
+ );
27
31
  }
28
32
  function generateThemesGroup(themes) {
29
- return themes.map((theme)=>({
30
- id: randomUUID(),
31
- name: theme,
32
- selectedTokenSets: {
33
- [`themes/${normalizeTokenSetName(theme)}`]: TokenSetStatus.ENABLED
34
- },
35
- group: 'Theme'
36
- }));
33
+ return themes.map(
34
+ (theme) => ({
35
+ id: randomUUID(),
36
+ name: theme,
37
+ selectedTokenSets: {
38
+ [`themes/${normalizeTokenSetName(theme)}`]: TokenSetStatus.ENABLED
39
+ },
40
+ group: "Theme"
41
+ })
42
+ );
37
43
  }
38
44
  function generateSemanticGroup() {
39
- return {
40
- id: randomUUID(),
41
- name: 'Semantic',
42
- selectedTokenSets: {
43
- 'semantic/style': TokenSetStatus.ENABLED,
44
- 'semantic/color': TokenSetStatus.ENABLED,
45
- 'primitives/globals': TokenSetStatus.SOURCE,
46
- 'primitives/typography/default': TokenSetStatus.SOURCE
47
- },
48
- group: 'Semantic'
49
- };
45
+ return {
46
+ id: randomUUID(),
47
+ name: "Semantic",
48
+ selectedTokenSets: {
49
+ "semantic/style": TokenSetStatus.ENABLED,
50
+ "semantic/color": TokenSetStatus.ENABLED,
51
+ "primitives/globals": TokenSetStatus.SOURCE,
52
+ "primitives/typography/default": TokenSetStatus.SOURCE
53
+ },
54
+ group: "Semantic"
55
+ };
50
56
  }
57
+ export {
58
+ generateThemesJson as default
59
+ };
@@ -1,7 +1,10 @@
1
1
  import { Argument } from "@commander-js/extra-typings";
2
2
  import { createTokensPackage } from "./createTokensPackage.js";
3
- export function makeInitCommand(command) {
4
- return command.showHelpAfterError().description('create an initial token structure for Designsystemet').addArgument(new Argument('<targetDir>', 'Target directory for the generated code')).action(async (targetDir)=>{
5
- await createTokensPackage(targetDir);
6
- });
3
+ function makeInitCommand(command) {
4
+ return command.showHelpAfterError().description("create an initial token structure for Designsystemet").addArgument(new Argument("<targetDir>", "Target directory for the generated code")).action(async (targetDir) => {
5
+ await createTokensPackage(targetDir);
6
+ });
7
7
  }
8
+ export {
9
+ makeInitCommand
10
+ };
@@ -1,12 +1,11 @@
1
1
  import { normalizeTokenSetName, toGeneratedCssFileName } from "./utils.js";
2
- export function nextStepsMarkdown(themes, modes, tokensTargetDir, packageName) {
3
- const themeModeCombinations = themes.flatMap((theme)=>modes.map((mode)=>[
4
- theme,
5
- mode
6
- ]));
7
- const themeOrThemes = `theme${themes.length > 1 ? 's' : ''}`;
8
- const isOrAre = themes.length > 1 ? 'are' : 'is';
9
- return `
2
+ function nextStepsMarkdown(themes, modes, tokensTargetDir, packageName) {
3
+ const themeModeCombinations = themes.flatMap(
4
+ (theme) => modes.map((mode) => [theme, mode])
5
+ );
6
+ const themeOrThemes = `theme${themes.length > 1 ? "s" : ""}`;
7
+ const isOrAre = themes.length > 1 ? "are" : "is";
8
+ return `
10
9
  ## Next steps
11
10
 
12
11
  ### Using the ${themeOrThemes} in Figma
@@ -23,14 +22,14 @@ export function nextStepsMarkdown(themes, modes, tokensTargetDir, packageName) {
23
22
 
24
23
  1. Go to https://theme.designsystemet.no and set up a color theme
25
24
  2. Press "Kopier tema"
26
- 3. Under "Json til Figma", copy the contents under ${modes.join(' / ')} to
25
+ 3. Under "Json til Figma", copy the contents under ${modes.join(" / ")} to
27
26
  the corresponding file under \`${tokensTargetDir}\`:
28
- ${themeModeCombinations.map(([theme, mode])=>` **${theme}, ${mode}**: \`primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}.json\` `).join('\n')}
27
+ ${themeModeCombinations.map(([theme, mode]) => ` **${theme}, ${mode}**: \`primitives/colors/${normalizeTokenSetName(mode)}/${normalizeTokenSetName(theme)}.json\` `).join("\n")}
29
28
  This can also be done in Tokens Studio for Figma.
30
29
  4. **IMPORTANT!** In the JSON data you copied, replace \`theme\` on line 2
31
30
  with the correct theme identifier, depending on the theme you're customizing.
32
- This is the same as the json filename without extension (e.g. ${themes.map((x)=>`\`${normalizeTokenSetName(x)}\``).join(', ')}).
33
- ${themes.length > 1 ? '5. Repeat steps 1—4 for the remaining themes' : ''}
31
+ This is the same as the json filename without extension (e.g. ${themes.map((x) => `\`${normalizeTokenSetName(x)}\``).join(", ")}).
32
+ ${themes.length > 1 ? "5. Repeat steps 1\u20144 for the remaining themes" : ""}
34
33
 
35
34
  ### Using the correct ${themeOrThemes} in Figma components
36
35
 
@@ -86,5 +85,8 @@ ${themes.length > 1 ? `
86
85
  \`\`\`js
87
86
  import '${packageName}/${toGeneratedCssFileName(themes[1])}';
88
87
  \`\`\`
89
- `.trim() : ''}`;
88
+ `.trim() : ""}`;
90
89
  }
90
+ export {
91
+ nextStepsMarkdown
92
+ };