@navikt/aksel 7.34.0 → 7.35.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 (35) hide show
  1. package/README.md +96 -2
  2. package/dist/codemod/codeshift.utils.js +9 -1
  3. package/dist/codemod/migrations.js +75 -22
  4. package/dist/codemod/run-codeshift.js +14 -3
  5. package/dist/codemod/transforms/v8.0.0/accordion-variant/accordion-variant.js +16 -0
  6. package/dist/codemod/transforms/{darkside/box-to-boxnew/box-to-boxnew.js → v8.0.0/box/box.js} +80 -100
  7. package/dist/codemod/transforms/v8.0.0/box-new/box-new.js +91 -0
  8. package/dist/codemod/transforms/v8.0.0/chips-variant/chips-variant.js +31 -0
  9. package/dist/codemod/transforms/v8.0.0/list/list.js +218 -0
  10. package/dist/codemod/transforms/{darkside → v8.0.0}/prop-deprecate/prop-deprecate.js +1 -1
  11. package/dist/codemod/transforms/v8.0.0/tag-variant/tag-variant.js +38 -0
  12. package/dist/codemod/transforms/v8.0.0/toggle-group-variant/toggle-group-variant.js +16 -0
  13. package/dist/codemod/utils/ast.js +1 -1
  14. package/dist/codemod/utils/check.js +35 -0
  15. package/dist/codemod/utils/move-variant-to-data-color.js +120 -0
  16. package/dist/darkside/index.js +3 -9
  17. package/dist/darkside/run-tooling.js +138 -42
  18. package/dist/darkside/tasks/print-remaining.js +143 -38
  19. package/dist/darkside/tasks/status.js +147 -30
  20. package/dist/darkside/transforms/darkside-tokens-css.js +23 -8
  21. package/dist/darkside/transforms/darkside-tokens-tailwind.js +9 -10
  22. package/dist/help.js +0 -10
  23. package/dist/index.js +14 -17
  24. package/package.json +7 -7
  25. package/dist/css-imports/config.js +0 -5
  26. package/dist/css-imports/generate-output.js +0 -147
  27. package/dist/css-imports/get-directories.js +0 -34
  28. package/dist/css-imports/get-version.js +0 -28
  29. package/dist/css-imports/index.js +0 -187
  30. package/dist/css-imports/inquiry.js +0 -35
  31. package/dist/css-imports/scan-code.js +0 -45
  32. /package/dist/codemod/transforms/{spacing → v8.0.0}/primitives-spacing/spacing.js +0 -0
  33. /package/dist/codemod/transforms/{spacing → v8.0.0}/spacing.utils.js +0 -0
  34. /package/dist/codemod/transforms/{spacing → v8.0.0}/token-spacing/spacing.js +0 -0
  35. /package/dist/codemod/transforms/{spacing → v8.0.0}/token-spacing-js/spacing.js +0 -0
@@ -63,50 +63,46 @@ const TRANSFORMS = {
63
63
  "js-tokens": "./transforms/darkside-tokens-js",
64
64
  "tailwind-tokens": "./transforms/darkside-tokens-tailwind",
65
65
  };
66
- const TASK_MENU = {
67
- type: "select",
68
- name: "task",
69
- message: "Task",
70
- initial: "status",
71
- choices: [
72
- { message: "Check status", name: "status" },
73
- { message: "Print remaining tokens", name: "print-remaining-tokens" },
74
- { message: "Migrate CSS tokens", name: "css-tokens" },
75
- { message: "Migrate Scss tokens", name: "scss-tokens" },
76
- { message: "Migrate Less tokens", name: "less-tokens" },
77
- { message: "Migrate JS tokens", name: "js-tokens" },
78
- { message: "Migrate tailwind tokens", name: "tailwind-tokens" },
79
- { message: "Run all migrations", name: "run-all-migrations" },
80
- { message: "Exit", name: "exit" },
81
- ],
82
- };
83
66
  /**
84
67
  * Main entry point for the tooling system
85
68
  */
86
69
  function runTooling(options, program) {
87
70
  return __awaiter(this, void 0, void 0, function* () {
88
71
  var _a;
72
+ console.info(chalk_1.default.greenBright.bold("\nWelcome to the Aksel v8 token migration tool!"));
73
+ const globList = (_a = options.glob) !== null && _a !== void 0 ? _a : (0, codeshift_utils_1.getDefaultGlob)(options === null || options === void 0 ? void 0 : options.ext);
74
+ console.info(chalk_1.default.gray(`Using glob pattern(s): ${globList}\nWorking directory: ${process.cwd()}\n`));
89
75
  // Find matching files based on glob pattern
90
- const filepaths = fast_glob_1.default.sync([(_a = options.glob) !== null && _a !== void 0 ? _a : (0, codeshift_utils_1.getDefaultGlob)(options === null || options === void 0 ? void 0 : options.ext)], {
76
+ const filepaths = yield (0, fast_glob_1.default)(globList, {
91
77
  cwd: process.cwd(),
92
78
  ignore: codeshift_utils_1.GLOB_IGNORE_PATTERNS,
79
+ /**
80
+ * When globbing, do not follow symlinks to avoid processing files outside the directory.
81
+ * This is most likely to happen in monorepos where node_modules may contain symlinks to packages
82
+ * in other parts of the repo.
83
+ *
84
+ * While node_modules is already ignored via GLOB_IGNORE_PATTERNS, if user globs upwards (e.g., using '../src/**'),
85
+ * that ignore-pattern may be ignored, leading to unintended file processing.
86
+ */
87
+ followSymbolicLinks: false,
93
88
  });
94
89
  if (options.dryRun) {
95
90
  console.info(chalk_1.default.yellow("Running in dry-run mode, no changes will be made"));
96
91
  }
97
92
  // Show initial status
98
- (0, status_1.getStatus)(filepaths);
93
+ const initialStatus = (0, status_1.getStatus)(filepaths);
99
94
  // Task execution loop
100
- let task = yield getNextTask();
95
+ let task = yield getNextTask(initialStatus.status);
96
+ let currentStatus = initialStatus;
101
97
  while (task !== "exit") {
102
98
  console.info("\n\n");
103
99
  try {
104
- yield executeTask(task, filepaths, options, program);
100
+ currentStatus = yield executeTask(task, filepaths, options, program, currentStatus, () => (0, status_1.getStatus)(filepaths, "no-print"));
105
101
  }
106
102
  catch (error) {
107
103
  program.error(chalk_1.default.red("Error:", error.message));
108
104
  }
109
- task = yield getNextTask();
105
+ task = yield getNextTask(currentStatus.status);
110
106
  }
111
107
  process.exit(0);
112
108
  });
@@ -114,27 +110,34 @@ function runTooling(options, program) {
114
110
  /**
115
111
  * Executes the selected task
116
112
  */
117
- function executeTask(task, filepaths, options, program) {
113
+ function executeTask(task, filepaths, options, program, statusStore, updateStatus) {
118
114
  return __awaiter(this, void 0, void 0, function* () {
119
115
  switch (task) {
120
116
  case "status":
121
- (0, status_1.getStatus)(filepaths);
122
- break;
123
- case "print-remaining-tokens":
124
- (0, print_remaining_1.printRemaining)(filepaths);
125
- break;
117
+ return updateStatus();
118
+ case "print-remaining-tokens": {
119
+ const newStatus = updateStatus();
120
+ yield (0, print_remaining_1.printRemaining)(filepaths, newStatus.status);
121
+ return newStatus;
122
+ }
126
123
  case "css-tokens":
127
124
  case "scss-tokens":
128
125
  case "less-tokens":
129
126
  case "js-tokens":
130
127
  case "tailwind-tokens": {
131
- const updatedStatus = (0, status_1.getStatus)(filepaths, "no-print").status;
132
- const scopedFiles = getScopedFilesForTask(task, filepaths, updatedStatus);
133
- yield runCodeshift(task, scopedFiles, {
128
+ if (!options.force) {
129
+ (0, validation_1.validateGit)(options, program);
130
+ }
131
+ const scopedFiles = getScopedFilesForTask(task, filepaths, statusStore.status);
132
+ const tokensBefore = getTokenCount(statusStore.status, task);
133
+ const stats = yield runCodeshift(task, scopedFiles, {
134
134
  dryRun: options.dryRun,
135
135
  force: options.force,
136
136
  });
137
- break;
137
+ const newStatus = updateStatus();
138
+ const tokensAfter = getTokenCount(newStatus.status, task);
139
+ printSummary(task, stats, tokensBefore, tokensAfter);
140
+ return newStatus;
138
141
  }
139
142
  case "run-all-migrations": {
140
143
  const tasks = [
@@ -144,20 +147,45 @@ function executeTask(task, filepaths, options, program) {
144
147
  "js-tokens",
145
148
  "tailwind-tokens",
146
149
  ];
150
+ if (!options.force) {
151
+ (0, validation_1.validateGit)(options, program);
152
+ }
153
+ let currentStatus = statusStore;
154
+ const summaryData = [];
147
155
  for (const migrationTask of tasks) {
148
- if (!options.force) {
149
- (0, validation_1.validateGit)(options, program);
150
- }
151
156
  console.info(`\nRunning ${migrationTask}...`);
152
- yield runCodeshift(migrationTask, filepaths, {
157
+ const scopedFiles = getScopedFilesForTask(migrationTask, filepaths, currentStatus.status);
158
+ const tokensBefore = getTokenCount(currentStatus.status, migrationTask);
159
+ const stats = yield runCodeshift(migrationTask, scopedFiles, {
153
160
  dryRun: options.dryRun,
154
161
  force: true,
155
162
  });
163
+ currentStatus = updateStatus();
164
+ const tokensAfter = getTokenCount(currentStatus.status, migrationTask);
165
+ summaryData.push({
166
+ task: migrationTask,
167
+ stats,
168
+ tokensBefore,
169
+ tokensAfter,
170
+ });
171
+ }
172
+ console.info(chalk_1.default.bold(`\nMigration Summary:`));
173
+ console.info("-".repeat(60));
174
+ for (const data of summaryData) {
175
+ const replaced = data.tokensBefore - data.tokensAfter;
176
+ const remaining = data.tokensAfter;
177
+ const icon = remaining === 0 ? "✨" : "⚠️";
178
+ console.info(`${chalk_1.default.bold(data.task)}:`);
179
+ console.info(` Files changed: ${data.stats.ok}`);
180
+ console.info(` Tokens replaced: ${replaced}`);
181
+ console.info(` ${icon} Remaining: ${remaining}`);
182
+ console.info("");
156
183
  }
157
- break;
184
+ return currentStatus;
158
185
  }
159
186
  default:
160
187
  program.error(chalk_1.default.red(`Unknown task: ${task}`));
188
+ return statusStore;
161
189
  }
162
190
  });
163
191
  }
@@ -201,7 +229,7 @@ function runCodeshift(task, filepaths, options) {
201
229
  throw new Error(`No transform found for task: ${task}`);
202
230
  }
203
231
  const codemodPath = node_path_1.default.join(__dirname, `${TRANSFORMS[task]}.js`);
204
- yield jscodeshift.run(codemodPath, filepaths, {
232
+ return yield jscodeshift.run(codemodPath, filepaths, {
205
233
  babel: true,
206
234
  ignorePattern: codeshift_utils_1.GLOB_IGNORE_PATTERNS,
207
235
  parser: "tsx",
@@ -218,12 +246,52 @@ function runCodeshift(task, filepaths, options) {
218
246
  /**
219
247
  * Prompts the user for the next task to run
220
248
  */
221
- function getNextTask() {
249
+ function getNextTask(status) {
222
250
  return __awaiter(this, void 0, void 0, function* () {
251
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
252
+ const getMessage = (base, tokens) => {
253
+ if (!status)
254
+ return base;
255
+ const fileCount = new Set(tokens.map((t) => t.fileName)).size;
256
+ if (fileCount === 0)
257
+ return `${base} (Done)`;
258
+ return `${base} (${fileCount} files)`;
259
+ };
260
+ const choices = [
261
+ { message: "Check status", name: "status" },
262
+ { message: "Print status", name: "print-remaining-tokens" },
263
+ {
264
+ message: getMessage("Migrate CSS tokens", (_b = (_a = status === null || status === void 0 ? void 0 : status.css) === null || _a === void 0 ? void 0 : _a.legacy) !== null && _b !== void 0 ? _b : []),
265
+ name: "css-tokens",
266
+ },
267
+ {
268
+ message: getMessage("Migrate Scss tokens", (_d = (_c = status === null || status === void 0 ? void 0 : status.scss) === null || _c === void 0 ? void 0 : _c.legacy) !== null && _d !== void 0 ? _d : []),
269
+ name: "scss-tokens",
270
+ },
271
+ {
272
+ message: getMessage("Migrate Less tokens", (_f = (_e = status === null || status === void 0 ? void 0 : status.less) === null || _e === void 0 ? void 0 : _e.legacy) !== null && _f !== void 0 ? _f : []),
273
+ name: "less-tokens",
274
+ },
275
+ {
276
+ message: getMessage("Migrate JS tokens", (_h = (_g = status === null || status === void 0 ? void 0 : status.js) === null || _g === void 0 ? void 0 : _g.legacy) !== null && _h !== void 0 ? _h : []),
277
+ name: "js-tokens",
278
+ },
279
+ {
280
+ message: getMessage("Migrate tailwind tokens", (_k = (_j = status === null || status === void 0 ? void 0 : status.tailwind) === null || _j === void 0 ? void 0 : _j.legacy) !== null && _k !== void 0 ? _k : []),
281
+ name: "tailwind-tokens",
282
+ },
283
+ { message: "Run all migrations", name: "run-all-migrations" },
284
+ { message: "Exit", name: "exit" },
285
+ ];
223
286
  try {
224
- const response = yield enquirer_1.default.prompt([
225
- Object.assign(Object.assign({}, TASK_MENU), { onCancel: () => process.exit(1) }),
226
- ]);
287
+ const response = yield enquirer_1.default.prompt({
288
+ type: "select",
289
+ name: "task",
290
+ message: "Task",
291
+ initial: "status",
292
+ choices,
293
+ onCancel: () => process.exit(1),
294
+ });
227
295
  return response.task;
228
296
  }
229
297
  catch (error) {
@@ -238,3 +306,31 @@ function getNextTask() {
238
306
  }
239
307
  });
240
308
  }
309
+ function getTokenCount(status, task) {
310
+ switch (task) {
311
+ case "css-tokens":
312
+ return status.css.legacy.length;
313
+ case "scss-tokens":
314
+ return status.scss.legacy.length;
315
+ case "less-tokens":
316
+ return status.less.legacy.length;
317
+ case "js-tokens":
318
+ return status.js.legacy.length;
319
+ case "tailwind-tokens":
320
+ return status.tailwind.legacy.length;
321
+ default:
322
+ return 0;
323
+ }
324
+ }
325
+ function printSummary(task, stats, tokensBefore, tokensAfter) {
326
+ console.info(chalk_1.default.bold(`\nMigration Summary for ${task}:`));
327
+ console.info("-".repeat(40));
328
+ console.info(`✅ Files changed: ${stats.ok}`);
329
+ console.info(`✅ Tokens replaced: ${tokensBefore - tokensAfter}`);
330
+ if (tokensAfter > 0) {
331
+ console.info(chalk_1.default.yellow(`⚠️ Tokens remaining: ${tokensAfter} (manual intervention needed)`));
332
+ }
333
+ else {
334
+ console.info(chalk_1.default.green(`✨ Tokens remaining: ${tokensAfter}`));
335
+ }
336
+ }
@@ -1,51 +1,156 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
5
14
  Object.defineProperty(exports, "__esModule", { value: true });
6
15
  exports.printRemaining = printRemaining;
16
+ const clipboardy_1 = __importDefault(require("clipboardy"));
17
+ const enquirer_1 = __importDefault(require("enquirer"));
7
18
  const node_path_1 = __importDefault(require("node:path"));
8
19
  const status_1 = require("./status");
9
- function printRemaining(files) {
10
- process.stdout.write("\nAnalyzing...");
11
- const statusObj = (0, status_1.getStatus)(files, "no-print").status;
12
- Object.entries(statusObj).forEach(([tokenType, data]) => {
13
- console.group(`\n${tokenType.toUpperCase()}:`);
14
- const fileLinks = [];
15
- data.legacy.forEach((tokenData) => {
16
- fileLinks.push(`${tokenData.name.replace(":", "")}:${tokenData.fileName}:${tokenData.lineNumber}:${tokenData.columnNumber}`);
17
- });
18
- if (fileLinks.length === 0) {
19
- console.info("Nothing to update.");
20
- console.groupEnd();
20
+ function printRemaining(files, status) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ process.stdout.write("\nAnalyzing...");
23
+ /**
24
+ * Skip re-calculating status if already provided
25
+ */
26
+ const statusObj = status !== null && status !== void 0 ? status : (0, status_1.getStatus)(files, "no-print").status;
27
+ /* Flatten all legacy tokens */
28
+ const allTokens = Object.values(statusObj).flatMap((data) => data.legacy);
29
+ if (allTokens.length === 0) {
30
+ console.info("\nNo legacy tokens found!");
31
+ return;
21
32
  }
22
- // Ensure every string is unique
23
- const uniqueFileLinks = Array.from(new Set(fileLinks));
24
- // Sort the unique fileLinks based on fileName first, lineNumber second, and columnNumber third
25
- uniqueFileLinks.sort((a, b) => {
26
- const [fileA, lineA, columnA] = a.split(":");
27
- const [fileB, lineB, columnB] = b.split(":");
28
- if (fileA !== fileB) {
29
- return fileA.localeCompare(fileB);
30
- }
31
- if (Number(lineA) !== Number(lineB)) {
32
- return Number(lineA) - Number(lineB);
33
- }
34
- return Number(columnA) - Number(columnB);
35
- });
36
- // Print the unique and sorted fileLinks as clickable links with full path
37
- uniqueFileLinks.forEach((link) => {
38
- const [tokenName, fileName, lineNumber, columnNumber] = link.split(":");
39
- const fullPath = node_path_1.default.resolve(process.cwd(), fileName);
40
- const withComment = data.legacy.find((token) => {
41
- return token.name === tokenName && token.comment;
33
+ const response = yield enquirer_1.default.prompt([
34
+ {
35
+ type: "select",
36
+ name: "groupBy",
37
+ message: "How would you like to group the remaining tokens?",
38
+ choices: [
39
+ { message: "By File", name: "file" },
40
+ { message: "By Token", name: "token" },
41
+ ],
42
+ },
43
+ {
44
+ type: "confirm",
45
+ name: "copy",
46
+ message: "Copy report to clipboard?",
47
+ initial: true,
48
+ },
49
+ ]);
50
+ const { groupBy, copy } = response;
51
+ console.info("\n");
52
+ const log = (str, indent = 0) => {
53
+ const prefix = " ".repeat(indent);
54
+ console.info(prefix + str);
55
+ };
56
+ let jsonOutput;
57
+ /**
58
+ * Group by filename
59
+ */
60
+ if (groupBy === "file") {
61
+ const byFile = new Map();
62
+ allTokens.forEach((token) => {
63
+ if (!byFile.has(token.fileName)) {
64
+ byFile.set(token.fileName, []);
65
+ }
66
+ byFile.get(token.fileName).push(token);
67
+ });
68
+ /* Sort files by number of tokens (descending) */
69
+ const sortedFiles = Array.from(byFile.entries()).sort((a, b) => b[1].length - a[1].length);
70
+ const fileOutput = [];
71
+ sortedFiles.forEach(([fileName, tokens]) => {
72
+ const fullPath = node_path_1.default.resolve(process.cwd(), fileName);
73
+ log(`${fileName} (${tokens.length} tokens)`);
74
+ /* Sort tokens in file by line number */
75
+ tokens.sort((a, b) => a.lineNumber - b.lineNumber);
76
+ const fileEntry = {
77
+ file: fileName,
78
+ fullPath,
79
+ count: tokens.length,
80
+ tokens: [],
81
+ };
82
+ tokens.forEach((token) => {
83
+ if (token.comment) {
84
+ log(`/* ${token.comment} */`, 1);
85
+ }
86
+ log(`${token.name}: ${fullPath}:${token.lineNumber}:${token.columnNumber}`, 1);
87
+ fileEntry.tokens.push({
88
+ name: token.name,
89
+ line: token.lineNumber,
90
+ column: token.columnNumber,
91
+ comment: token.comment,
92
+ link: `file://${fullPath}`,
93
+ });
94
+ });
95
+ /* Empty line */
96
+ log("");
97
+ fileOutput.push(fileEntry);
42
98
  });
43
- if (withComment) {
44
- console.info(`\n/* ${withComment.comment} */`);
99
+ jsonOutput = fileOutput;
100
+ }
101
+ else {
102
+ /* Group by token name */
103
+ const byToken = new Map();
104
+ allTokens.forEach((token) => {
105
+ if (!byToken.has(token.name)) {
106
+ byToken.set(token.name, []);
107
+ }
108
+ byToken.get(token.name).push(token);
109
+ });
110
+ /* Sort tokens by frequency (descending) */
111
+ const sortedTokens = Array.from(byToken.entries()).sort((a, b) => b[1].length - a[1].length);
112
+ const tokenOutput = [];
113
+ sortedTokens.forEach(([tokenName, tokens]) => {
114
+ var _a;
115
+ log(`${tokenName} (${tokens.length} occurrences)`);
116
+ /**
117
+ * We can assume all comments are the same for a "tokenName"
118
+ */
119
+ const foundComment = (_a = tokens.find((t) => t.comment)) === null || _a === void 0 ? void 0 : _a.comment;
120
+ if (foundComment) {
121
+ log(`/* ${foundComment} */`, 1);
122
+ }
123
+ const tokenEntry = {
124
+ token: tokenName,
125
+ count: tokens.length,
126
+ occurrences: [],
127
+ };
128
+ tokens.forEach((token) => {
129
+ const fullPath = node_path_1.default.resolve(process.cwd(), token.fileName);
130
+ log(`${fullPath}:${token.lineNumber}:${token.columnNumber}`, 1);
131
+ tokenEntry.occurrences.push({
132
+ file: token.fileName,
133
+ fullPath,
134
+ line: token.lineNumber,
135
+ column: token.columnNumber,
136
+ comment: token.comment,
137
+ link: `file://${fullPath}`,
138
+ });
139
+ });
140
+ /* Empty line */
141
+ log("");
142
+ tokenOutput.push(tokenEntry);
143
+ });
144
+ jsonOutput = tokenOutput;
145
+ }
146
+ if (copy) {
147
+ try {
148
+ clipboardy_1.default.writeSync(JSON.stringify(jsonOutput, null, 2));
149
+ console.info("✅ Report (JSON) copied to clipboard!");
45
150
  }
46
- console.info(`${tokenName}: file://${fullPath}:${lineNumber}:${columnNumber}`);
47
- });
48
- console.groupEnd();
151
+ catch (error) {
152
+ console.error("❌ Failed to copy to clipboard:", error.message);
153
+ }
154
+ }
49
155
  });
50
- console.info("\n");
51
156
  }