@atlaskit/codemod-cli 0.27.4 → 0.28.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.
- package/CHANGELOG.md +15 -0
- package/dist/cjs/main.js +20 -15
- package/dist/cjs/presets/remove-token-fallbacks/remove-token-fallbacks.js +350 -43
- package/dist/cjs/presets/remove-token-fallbacks/utils/chunk.js +14 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/normalize-values.js +15 -9
- package/dist/cjs/presets/remove-token-fallbacks/utils/remove-unused-imports.js +2 -2
- package/dist/cjs/presets/remove-token-fallbacks/utils/reporter.js +28 -21
- package/dist/cjs/presets/remove-token-fallbacks/utils/token-processor.js +201 -71
- package/dist/es2019/main.js +7 -1
- package/dist/es2019/presets/remove-token-fallbacks/remove-token-fallbacks.js +164 -17
- package/dist/es2019/presets/remove-token-fallbacks/utils/chunk.js +8 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/normalize-values.js +15 -9
- package/dist/es2019/presets/remove-token-fallbacks/utils/remove-unused-imports.js +3 -3
- package/dist/es2019/presets/remove-token-fallbacks/utils/reporter.js +6 -1
- package/dist/es2019/presets/remove-token-fallbacks/utils/token-processor.js +121 -17
- package/dist/esm/main.js +20 -15
- package/dist/esm/presets/remove-token-fallbacks/remove-token-fallbacks.js +350 -41
- package/dist/esm/presets/remove-token-fallbacks/utils/chunk.js +8 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/normalize-values.js +15 -9
- package/dist/esm/presets/remove-token-fallbacks/utils/remove-unused-imports.js +2 -2
- package/dist/esm/presets/remove-token-fallbacks/utils/reporter.js +28 -21
- package/dist/esm/presets/remove-token-fallbacks/utils/token-processor.js +201 -71
- package/dist/types/presets/remove-token-fallbacks/remove-token-fallbacks.d.ts +9 -1
- package/dist/types/presets/remove-token-fallbacks/types.d.ts +8 -0
- package/dist/types/presets/remove-token-fallbacks/utils/chunk.d.ts +1 -0
- package/dist/types/presets/remove-token-fallbacks/utils/normalize-values.d.ts +2 -1
- package/dist/types/presets/remove-token-fallbacks/utils/token-processor.d.ts +6 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/remove-token-fallbacks.d.ts +9 -1
- package/dist/types-ts4.5/presets/remove-token-fallbacks/types.d.ts +8 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/chunk.d.ts +1 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/normalize-values.d.ts +2 -1
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/token-processor.d.ts +6 -0
- package/package.json +4 -4
|
@@ -7,6 +7,7 @@ import { hasImportDeclaration } from '@hypermod/utils';
|
|
|
7
7
|
import { findRoot } from '@manypkg/find-root';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import { getTokenMap } from './utils/all-tokens';
|
|
10
|
+
import { chunkArray } from './utils/chunk';
|
|
10
11
|
import { getTeamInfo } from './utils/get-team-info';
|
|
11
12
|
import { removeUnusedImports } from './utils/remove-unused-imports';
|
|
12
13
|
import { removeUnusedVariables } from './utils/remove-unused-variables';
|
|
@@ -27,6 +28,14 @@ const execAsync = promisify(exec);
|
|
|
27
28
|
* @param {boolean} [options.useLegacyColorTheme] - If true, uses the legacy theme for color token mapping.
|
|
28
29
|
* @param {string} [options.reportFolder] - Directory path to output transformation reports. Reports will be generated only if this option is provided.
|
|
29
30
|
* @param {boolean} [options.dry] - If true, performs a dry run without modifying the files.
|
|
31
|
+
* @param {string} [options.skipTokens] - A comma-separated list of token prefixes to exempt from automatic fallback removal. By default, 'border' tokens are always included in this list. Whether fallbacks for these tokens are removed when they exactly match depends on the preserveSkippedFallbacks option.
|
|
32
|
+
* @param {boolean} [options.preserveSkippedFallbacks] - If true, fallbacks for skipped tokens will never be removed, even if they exactly match the token value. If false (default), fallbacks for skipped tokens will be removed if they exactly match.
|
|
33
|
+
* @param {boolean} [options.skipEslint] - If true, skips running ESLint on modified files after transformation.
|
|
34
|
+
* @param {boolean} [options.skipPrettier] - If true, skips running Prettier on modified files after transformation.
|
|
35
|
+
* @param {number} [options.colorDifferenceThreshold] - The maximum allowed difference for color tokens to be considered acceptable for removal. Default is 15.
|
|
36
|
+
* @param {number} [options.spaceDifferenceThreshold] - The maximum allowed percentage difference for space tokens to be considered acceptable for removal. Default is 0.
|
|
37
|
+
* @param {number} [options.numericDifferenceThreshold] - The maximum allowed percentage difference for numeric tokens to be considered acceptable for removal. Default is 0.
|
|
38
|
+
* @param {number} [options.borderDifferenceThreshold] - The maximum allowed percentage difference for border tokens to be considered acceptable for removal. Default is 0.
|
|
30
39
|
*
|
|
31
40
|
* @returns {Promise<string>} A promise that resolves to the transformed source code as a string.
|
|
32
41
|
*/
|
|
@@ -45,6 +54,32 @@ export default async function transformer(fileInfo, {
|
|
|
45
54
|
};
|
|
46
55
|
if (options.verbose) {
|
|
47
56
|
console.log(chalk.yellow(`Using ${options.useLegacyColorTheme ? 'legacy light' : 'light'} theme.`));
|
|
57
|
+
if (options.skipTokens) {
|
|
58
|
+
console.log(chalk.yellow(`Auto fallback exemptions active for: ${options.skipTokens}`));
|
|
59
|
+
}
|
|
60
|
+
if (options.preserveSkippedFallbacks) {
|
|
61
|
+
console.log(chalk.yellow(`Preserving all fallbacks for skipped tokens, even if they match exactly.`));
|
|
62
|
+
}
|
|
63
|
+
if (options.skipEslint) {
|
|
64
|
+
console.log(chalk.yellow(`Skipping ESLint post-processing.`));
|
|
65
|
+
}
|
|
66
|
+
if (options.skipPrettier) {
|
|
67
|
+
console.log(chalk.yellow(`Skipping Prettier post-processing.`));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Log threshold values if they are set
|
|
71
|
+
if (options.colorDifferenceThreshold !== undefined) {
|
|
72
|
+
console.log(chalk.yellow(`Color difference threshold set to: ${options.colorDifferenceThreshold}`));
|
|
73
|
+
}
|
|
74
|
+
if (options.spaceDifferenceThreshold !== undefined) {
|
|
75
|
+
console.log(chalk.yellow(`Space difference threshold set to: ${options.spaceDifferenceThreshold}%`));
|
|
76
|
+
}
|
|
77
|
+
if (options.numericDifferenceThreshold !== undefined) {
|
|
78
|
+
console.log(chalk.yellow(`Numeric difference threshold set to: ${options.numericDifferenceThreshold}%`));
|
|
79
|
+
}
|
|
80
|
+
if (options.borderDifferenceThreshold !== undefined) {
|
|
81
|
+
console.log(chalk.yellow(`Border difference threshold set to: ${options.borderDifferenceThreshold}%`));
|
|
82
|
+
}
|
|
48
83
|
}
|
|
49
84
|
const tokenMap = getTokenMap((_options$useLegacyCol = options.useLegacyColorTheme) !== null && _options$useLegacyCol !== void 0 ? _options$useLegacyCol : false);
|
|
50
85
|
const teamInfo = await getTeamInfo(fileInfo.path);
|
|
@@ -59,6 +94,9 @@ export default async function transformer(fileInfo, {
|
|
|
59
94
|
});
|
|
60
95
|
const results = await Promise.all(transformPromises);
|
|
61
96
|
const unusedVars = [];
|
|
97
|
+
if (options.reportFolder) {
|
|
98
|
+
await writeReports(details, options.reportFolder);
|
|
99
|
+
}
|
|
62
100
|
if (results.some(result => result.fallbackRemoved)) {
|
|
63
101
|
const allImports = results.flatMap(result => {
|
|
64
102
|
var _result$resolvedImpor;
|
|
@@ -75,20 +113,22 @@ export default async function transformer(fileInfo, {
|
|
|
75
113
|
}
|
|
76
114
|
removeUnusedImports(allImports, j);
|
|
77
115
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (options.reportFolder) {
|
|
81
|
-
await writeReports(details, options.reportFolder);
|
|
82
|
-
}
|
|
83
|
-
if (options.dry) {
|
|
84
|
-
if (options.verbose) {
|
|
85
|
-
console.log(chalk.cyan(`${fileInfo.path}: dry run mode active. Source was not modified.`));
|
|
116
|
+
if (unusedVars.length) {
|
|
117
|
+
removeUnusedVariables(unusedVars, j);
|
|
86
118
|
}
|
|
119
|
+
if (options.dry) {
|
|
120
|
+
if (options.verbose) {
|
|
121
|
+
console.log(chalk.cyan(`${fileInfo.path}: dry run mode active. Source was not modified.`));
|
|
122
|
+
}
|
|
123
|
+
// Return the unmodified source if dryRun is true
|
|
124
|
+
return fileInfo.source;
|
|
125
|
+
} else {
|
|
126
|
+
// Return the transformed source
|
|
127
|
+
return source.toSource();
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
87
130
|
// Return the unmodified source if dryRun is true
|
|
88
131
|
return fileInfo.source;
|
|
89
|
-
} else {
|
|
90
|
-
// Return the transformed source
|
|
91
|
-
return source.toSource();
|
|
92
132
|
}
|
|
93
133
|
}
|
|
94
134
|
export const parser = 'tsx';
|
|
@@ -104,7 +144,7 @@ export async function beforeAll(options) {
|
|
|
104
144
|
|
|
105
145
|
/**
|
|
106
146
|
* Function executed after all transformations to combine individual file reports into a comprehensive transformation report.
|
|
107
|
-
* It also applies prettier to the affected files.
|
|
147
|
+
* It also applies prettier and eslint (to remove dangling suppressions) to the affected files.
|
|
108
148
|
*/
|
|
109
149
|
export async function afterAll(options) {
|
|
110
150
|
if (options.reportFolder) {
|
|
@@ -115,16 +155,123 @@ export async function afterAll(options) {
|
|
|
115
155
|
const filesTxtPath = path.join(options.reportFolder, 'files.txt');
|
|
116
156
|
const fileContent = await fs.readFile(filesTxtPath, 'utf-8');
|
|
117
157
|
if (fileContent.length > 0) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
158
|
+
const filePaths = fileContent.split(/\r?\n/).filter(Boolean);
|
|
159
|
+
|
|
160
|
+
// Get the first file path and strip any quotes
|
|
161
|
+
const firstFilePath = filePaths[0].replace(/^['"]|['"]$/g, '');
|
|
162
|
+
|
|
163
|
+
// Determine the root directory using findRoot
|
|
164
|
+
const rootDir = await findRoot(path.dirname(firstFilePath));
|
|
165
|
+
console.log('Root directory:', rootDir);
|
|
166
|
+
await gitStage(filePaths, rootDir);
|
|
167
|
+
if (!options.skipEslint) {
|
|
168
|
+
await runEslint(filePaths, rootDir);
|
|
169
|
+
} else if (options.verbose) {
|
|
170
|
+
console.log(chalk.blue('Skipping ESLint post-processing as requested.'));
|
|
171
|
+
}
|
|
172
|
+
if (!options.skipPrettier) {
|
|
173
|
+
await runPrettier(filePaths, rootDir);
|
|
174
|
+
} else if (options.verbose) {
|
|
175
|
+
console.log(chalk.blue('Skipping Prettier post-processing as requested.'));
|
|
176
|
+
}
|
|
121
177
|
}
|
|
122
178
|
} catch (error) {
|
|
123
179
|
if (error instanceof Error) {
|
|
124
|
-
console.error(chalk.red(`Unexpected error
|
|
180
|
+
console.error(chalk.red(`Unexpected error: ${error.message}`));
|
|
125
181
|
} else {
|
|
126
|
-
console.error(chalk.red('An unknown error occurred
|
|
182
|
+
console.error(chalk.red('An unknown error occurred.'));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function gitStage(filePaths, cwd) {
|
|
188
|
+
const gitAddCommand = `git add ${filePaths.join(' ')}`;
|
|
189
|
+
console.log(`Executing command: ${gitAddCommand}`);
|
|
190
|
+
const {
|
|
191
|
+
stdout: gitAddStdout,
|
|
192
|
+
stderr: gitAddStderr
|
|
193
|
+
} = await execAsync(gitAddCommand, {
|
|
194
|
+
cwd
|
|
195
|
+
});
|
|
196
|
+
if (gitAddStdout) {
|
|
197
|
+
console.log(chalk.blue(`Git add output:\n${gitAddStdout}`));
|
|
198
|
+
}
|
|
199
|
+
if (gitAddStderr) {
|
|
200
|
+
console.error(chalk.yellow(`Git add errors:\n${gitAddStderr}`));
|
|
201
|
+
}
|
|
202
|
+
console.log(chalk.green(`All changes have been staged.`));
|
|
203
|
+
}
|
|
204
|
+
async function runPrettier(filePaths, cwd) {
|
|
205
|
+
const prettierCommand = `yarn prettier --write ${filePaths.join(' ')}`;
|
|
206
|
+
console.log(`Executing command: ${prettierCommand}`);
|
|
207
|
+
const {
|
|
208
|
+
stdout: prettierStdout,
|
|
209
|
+
stderr: prettierStderr
|
|
210
|
+
} = await execAsync(prettierCommand, {
|
|
211
|
+
cwd
|
|
212
|
+
});
|
|
213
|
+
if (prettierStdout) {
|
|
214
|
+
console.log(chalk.blue(`Prettier output:\n${prettierStdout}`));
|
|
215
|
+
}
|
|
216
|
+
if (prettierStderr) {
|
|
217
|
+
console.error(chalk.yellow(`Prettier errors:\n${prettierStderr}`));
|
|
218
|
+
}
|
|
219
|
+
console.log(chalk.green(`Prettier was run successfully`));
|
|
220
|
+
}
|
|
221
|
+
async function runEslint(filePaths, cwd) {
|
|
222
|
+
const fileChunks = chunkArray(filePaths, 20);
|
|
223
|
+
const totalChunks = fileChunks.length;
|
|
224
|
+
for (const [chunkIndex, fileChunk] of fileChunks.entries()) {
|
|
225
|
+
const eslintCommand = `yarn eslint ${fileChunk.join(' ')} --report-unused-disable-directives --fix`;
|
|
226
|
+
console.log(`Executing command for chunk ${chunkIndex + 1} of ${totalChunks}: ${eslintCommand}`);
|
|
227
|
+
try {
|
|
228
|
+
const result = await execAsync(eslintCommand, {
|
|
229
|
+
cwd
|
|
230
|
+
});
|
|
231
|
+
const {
|
|
232
|
+
stdout,
|
|
233
|
+
stderr
|
|
234
|
+
} = result;
|
|
235
|
+
if (stdout) {
|
|
236
|
+
console.log(chalk.blue(`ESLint output for chunk ${chunkIndex + 1} of ${totalChunks}:\n${stdout}`));
|
|
237
|
+
}
|
|
238
|
+
if (stderr) {
|
|
239
|
+
console.error(chalk.yellow(`ESLint errors for chunk ${chunkIndex + 1} of ${totalChunks}:\n${stderr}`));
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error(chalk.red(`Error running ESLint on chunk ${chunkIndex + 1} of ${totalChunks}: ${error}`));
|
|
243
|
+
|
|
244
|
+
// Retry each file individually
|
|
245
|
+
console.log(chalk.yellow(`Retrying each file in chunk ${chunkIndex + 1} of ${totalChunks} individually...`));
|
|
246
|
+
|
|
247
|
+
// Chunk the files into smaller groups of 5 for parallel retry
|
|
248
|
+
const smallerChunks = chunkArray(fileChunk, 5);
|
|
249
|
+
const totalSmallerChunks = smallerChunks.length;
|
|
250
|
+
for (const [smallChunkIndex, smallerChunk] of smallerChunks.entries()) {
|
|
251
|
+
await Promise.all(smallerChunk.map(async file => {
|
|
252
|
+
try {
|
|
253
|
+
const individualEslintCommand = `yarn eslint ${file} --report-unused-disable-directives --fix`;
|
|
254
|
+
console.log(`Executing command for file in small chunk ${smallChunkIndex + 1} of ${totalSmallerChunks}: ${individualEslintCommand}`);
|
|
255
|
+
const result = await execAsync(individualEslintCommand, {
|
|
256
|
+
cwd
|
|
257
|
+
});
|
|
258
|
+
const {
|
|
259
|
+
stdout,
|
|
260
|
+
stderr
|
|
261
|
+
} = result;
|
|
262
|
+
if (stdout) {
|
|
263
|
+
console.log(chalk.blue(`ESLint output for file ${file} in small chunk ${smallChunkIndex + 1} of ${totalSmallerChunks}:\n${stdout}`));
|
|
264
|
+
}
|
|
265
|
+
if (stderr) {
|
|
266
|
+
console.error(chalk.yellow(`ESLint errors for file ${file} in small chunk ${smallChunkIndex + 1} of ${totalSmallerChunks}:\n${stderr}`));
|
|
267
|
+
}
|
|
268
|
+
} catch (fileError) {
|
|
269
|
+
console.error(chalk.red(`Error running ESLint on file ${file} in small chunk ${smallChunkIndex + 1} of ${totalSmallerChunks}: ${fileError}`));
|
|
270
|
+
}
|
|
271
|
+
}));
|
|
127
272
|
}
|
|
128
273
|
}
|
|
274
|
+
console.log(chalk.green(`Finished running ESLint for chunk ${chunkIndex + 1} of ${totalChunks}.`));
|
|
129
275
|
}
|
|
276
|
+
console.log(chalk.green(`ESLint was run on all files successfully`));
|
|
130
277
|
}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { colorToHex, compareHex, isValidColor } from './color-utils';
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
4
|
+
// Default threshold values
|
|
5
|
+
const DEFAULT_COLOR_DIFFERENCE = 15;
|
|
6
|
+
const DEFAULT_SPACE_DIFFERENCE = 0;
|
|
7
|
+
const DEFAULT_NUMERIC_DIFFERENCE = 0;
|
|
8
|
+
const DEFAULT_BORDER_DIFFERENCE = 0;
|
|
9
|
+
export function normalizeValues(tokenKey, tokenValue, fallbackValue, options) {
|
|
10
|
+
// Use options thresholds or defaults
|
|
11
|
+
const colorDifference = (options === null || options === void 0 ? void 0 : options.colorDifferenceThreshold) !== undefined ? options.colorDifferenceThreshold : DEFAULT_COLOR_DIFFERENCE;
|
|
12
|
+
const spaceDifference = (options === null || options === void 0 ? void 0 : options.spaceDifferenceThreshold) !== undefined ? options.spaceDifferenceThreshold : DEFAULT_SPACE_DIFFERENCE;
|
|
13
|
+
const numericDifference = (options === null || options === void 0 ? void 0 : options.numericDifferenceThreshold) !== undefined ? options.numericDifferenceThreshold : DEFAULT_NUMERIC_DIFFERENCE;
|
|
14
|
+
const borderDifference = (options === null || options === void 0 ? void 0 : options.borderDifferenceThreshold) !== undefined ? options.borderDifferenceThreshold : DEFAULT_BORDER_DIFFERENCE;
|
|
9
15
|
let tokenLogValue;
|
|
10
16
|
let fallbackLogValue;
|
|
11
17
|
let normalizedTokenValue = tokenValue;
|
|
@@ -26,15 +32,15 @@ export function normalizeValues(tokenKey, tokenValue, fallbackValue) {
|
|
|
26
32
|
}
|
|
27
33
|
if (normalizedTokenValue && normalizedFallbackValue) {
|
|
28
34
|
difference = compareHex(normalizedTokenValue, normalizedFallbackValue);
|
|
29
|
-
isAcceptableDifference = difference <=
|
|
35
|
+
isAcceptableDifference = difference <= colorDifference;
|
|
30
36
|
}
|
|
31
|
-
} else if (lowerCaseTokenKey.startsWith('space')) {
|
|
37
|
+
} else if (lowerCaseTokenKey.startsWith('space') || lowerCaseTokenKey.startsWith('border')) {
|
|
32
38
|
const tokenValueInPx = tokenValue ? convertToPx(tokenValue) : undefined;
|
|
33
39
|
const fallbackValueInPx = fallbackValue ? convertToPx(fallbackValue) : undefined;
|
|
34
40
|
if (tokenValueInPx !== undefined && fallbackValueInPx !== undefined) {
|
|
35
41
|
const maxVal = Math.max(tokenValueInPx, fallbackValueInPx);
|
|
36
42
|
difference = Math.abs(tokenValueInPx - fallbackValueInPx) / maxVal * 100;
|
|
37
|
-
isAcceptableDifference = difference <=
|
|
43
|
+
isAcceptableDifference = difference <= (lowerCaseTokenKey.startsWith('space') ? spaceDifference : borderDifference);
|
|
38
44
|
}
|
|
39
45
|
// Log the normalized values
|
|
40
46
|
normalizedTokenValue = tokenValue;
|
|
@@ -48,7 +54,7 @@ export function normalizeValues(tokenKey, tokenValue, fallbackValue) {
|
|
|
48
54
|
if (!isNaN(tokenValueNumber) && !isNaN(fallbackValueNumber)) {
|
|
49
55
|
const maxVal = Math.max(tokenValueNumber, fallbackValueNumber);
|
|
50
56
|
difference = Math.abs(tokenValueNumber - fallbackValueNumber) / maxVal * 100;
|
|
51
|
-
isAcceptableDifference = difference <=
|
|
57
|
+
isAcceptableDifference = difference <= numericDifference;
|
|
52
58
|
}
|
|
53
59
|
// Log the normalized values
|
|
54
60
|
normalizedTokenValue = tokenValue;
|
|
@@ -35,13 +35,13 @@ export function removeUnusedImports(importDeclarations, j) {
|
|
|
35
35
|
return j(importDeclaration).find(j.ImportSpecifier).filter(s => removeIfUnused(s, importDeclaration)).size() > 0;
|
|
36
36
|
};
|
|
37
37
|
const processImportDeclaration = importDeclaration => {
|
|
38
|
-
var _importDeclaration$va, _importDeclaration$va2;
|
|
39
|
-
if (((_importDeclaration$va = importDeclaration.value
|
|
38
|
+
var _importDeclaration$va, _importDeclaration$va2, _importDeclaration$va3, _importDeclaration$va4;
|
|
39
|
+
if (((_importDeclaration$va = importDeclaration.value) === null || _importDeclaration$va === void 0 ? void 0 : (_importDeclaration$va2 = _importDeclaration$va.specifiers) === null || _importDeclaration$va2 === void 0 ? void 0 : _importDeclaration$va2.length) === 0) {
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
const hadUnusedDefaultImport = removeUnusedDefaultImport(importDeclaration);
|
|
43
43
|
const hadUnusedNonDefaultImports = removeUnusedNonDefaultImports(importDeclaration);
|
|
44
|
-
if (((_importDeclaration$
|
|
44
|
+
if (((_importDeclaration$va3 = importDeclaration.value) === null || _importDeclaration$va3 === void 0 ? void 0 : (_importDeclaration$va4 = _importDeclaration$va3.specifiers) === null || _importDeclaration$va4 === void 0 ? void 0 : _importDeclaration$va4.length) === 0) {
|
|
45
45
|
j(importDeclaration).remove();
|
|
46
46
|
return true;
|
|
47
47
|
}
|
|
@@ -25,6 +25,10 @@ function escapeCsvValue(value) {
|
|
|
25
25
|
}
|
|
26
26
|
export async function clearFolder(reportFolder) {
|
|
27
27
|
console.log('Clearing report folder:', reportFolder);
|
|
28
|
+
// Create the folder if it doesn't exist
|
|
29
|
+
await fs.mkdir(reportFolder, {
|
|
30
|
+
recursive: true
|
|
31
|
+
});
|
|
28
32
|
const filesToDelete = await fs.readdir(reportFolder);
|
|
29
33
|
for (const file of filesToDelete) {
|
|
30
34
|
const filePath = path.join(reportFolder, file);
|
|
@@ -33,7 +37,8 @@ export async function clearFolder(reportFolder) {
|
|
|
33
37
|
}
|
|
34
38
|
async function saveFilePaths(reportFolder, files) {
|
|
35
39
|
const filesTxtPath = path.join(reportFolder, 'files.txt');
|
|
36
|
-
|
|
40
|
+
const sortedFiles = Array.from(files).sort(); // Sort the file paths alphabetically
|
|
41
|
+
await fs.writeFile(filesTxtPath, sortedFiles.map(filePath => `"${filePath}"`).join('\n'), 'utf-8');
|
|
37
42
|
}
|
|
38
43
|
export async function combineReports(reportFolder) {
|
|
39
44
|
console.log('Combining reports in folder:', reportFolder);
|
|
@@ -45,6 +45,29 @@ export class TokenProcessor {
|
|
|
45
45
|
logError(message) {
|
|
46
46
|
this.log(chalk.red(message));
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Checks if a token should be exempted from automatic fallback removal
|
|
51
|
+
* @param tokenKey The token key to check
|
|
52
|
+
* @returns An object containing whether the token should be exempted and related information
|
|
53
|
+
*/
|
|
54
|
+
checkTokenExemption(tokenKey) {
|
|
55
|
+
// Create exemption list from user-provided skipTokens, and always include 'border'
|
|
56
|
+
const userExemptions = this.options.skipTokens ? this.options.skipTokens.split(',').map(item => item.trim()) : [];
|
|
57
|
+
|
|
58
|
+
// Always include 'border' in the exemption list
|
|
59
|
+
const exemptionList = [...userExemptions];
|
|
60
|
+
if (!exemptionList.includes('border')) {
|
|
61
|
+
exemptionList.push('border');
|
|
62
|
+
}
|
|
63
|
+
const isExemptedToken = exemptionList.some(prefix => tokenKey.startsWith(prefix));
|
|
64
|
+
const exemptedPrefix = isExemptedToken ? exemptionList.find(prefix => tokenKey.startsWith(prefix)) || null : null;
|
|
65
|
+
return {
|
|
66
|
+
shouldBeExempted: isExemptedToken,
|
|
67
|
+
exemptedPrefix,
|
|
68
|
+
exemptionList
|
|
69
|
+
};
|
|
70
|
+
}
|
|
48
71
|
async processSingleToken(callPath) {
|
|
49
72
|
var _callPath$node$loc2;
|
|
50
73
|
const args = callPath.node.arguments;
|
|
@@ -67,20 +90,14 @@ export class TokenProcessor {
|
|
|
67
90
|
resolvedLocalVarDeclaration: undefined
|
|
68
91
|
};
|
|
69
92
|
}
|
|
70
|
-
const
|
|
71
|
-
const tokenValue = isSkipped ? '' : this.tokenMap[tokenKey];
|
|
93
|
+
const tokenValue = this.tokenMap[tokenKey];
|
|
72
94
|
this.logVerbose(`Token value from tokenMap: ${chalk.magenta(tokenValue)} for key: ${chalk.yellow(tokenKey)}`);
|
|
73
95
|
const {
|
|
74
96
|
rawFallbackValue,
|
|
75
97
|
fallbackValue,
|
|
76
98
|
resolvedImportDeclaration,
|
|
77
99
|
resolvedLocalVarDeclaration
|
|
78
|
-
} =
|
|
79
|
-
rawFallbackValue: 'N/A',
|
|
80
|
-
fallbackValue: undefined,
|
|
81
|
-
resolvedImportDeclaration: undefined,
|
|
82
|
-
resolvedLocalVarDeclaration: undefined
|
|
83
|
-
} : await this.getFallbackValue(args[1]);
|
|
100
|
+
} = await this.getFallbackValue(args[1]);
|
|
84
101
|
const {
|
|
85
102
|
difference,
|
|
86
103
|
isAcceptableDifference,
|
|
@@ -88,7 +105,7 @@ export class TokenProcessor {
|
|
|
88
105
|
fallbackLogValue,
|
|
89
106
|
normalizedTokenValue,
|
|
90
107
|
normalizedFallbackValue
|
|
91
|
-
} = normalizeValues(tokenKey, tokenValue, fallbackValue);
|
|
108
|
+
} = normalizeValues(tokenKey, tokenValue, fallbackValue, this.options);
|
|
92
109
|
const areEqual = normalizedTokenValue === normalizedFallbackValue;
|
|
93
110
|
const logData = {
|
|
94
111
|
teamInfo: this.teamInfo,
|
|
@@ -103,7 +120,22 @@ export class TokenProcessor {
|
|
|
103
120
|
let fallbackRemoved = false;
|
|
104
121
|
let importDeclaration;
|
|
105
122
|
let localVarDeclaration;
|
|
106
|
-
|
|
123
|
+
|
|
124
|
+
// Check if token should be exempted
|
|
125
|
+
const {
|
|
126
|
+
shouldBeExempted,
|
|
127
|
+
exemptedPrefix
|
|
128
|
+
} = this.checkTokenExemption(tokenKey);
|
|
129
|
+
|
|
130
|
+
// Determine if we should modify this token based on the exemption status and settings
|
|
131
|
+
const shouldModifyToken =
|
|
132
|
+
// Always modify if not exempted and values match
|
|
133
|
+
areEqual && !shouldBeExempted ||
|
|
134
|
+
// Or if values don't exactly match but are acceptable to modify and not exempted
|
|
135
|
+
(isAcceptableDifference || this.options.forceUpdate) && !shouldBeExempted ||
|
|
136
|
+
// Or if exempted but values match exactly and we're not preserving skipped fallbacks
|
|
137
|
+
areEqual && shouldBeExempted && !this.options.preserveSkippedFallbacks;
|
|
138
|
+
if (shouldModifyToken) {
|
|
107
139
|
this.log(chalk.green(areEqual ? 'Token value and fallback value are equal, removing fallback' : 'Token value and fallback value are within acceptable difference threshold, removing fallback'));
|
|
108
140
|
args.pop();
|
|
109
141
|
this.details.replaced.push(logData);
|
|
@@ -111,7 +143,7 @@ export class TokenProcessor {
|
|
|
111
143
|
importDeclaration = resolvedImportDeclaration;
|
|
112
144
|
localVarDeclaration = resolvedLocalVarDeclaration;
|
|
113
145
|
} else {
|
|
114
|
-
const message = normalizedFallbackValue === undefined ? `Fallback value could not be resolved` : `Values mismatched significantly`;
|
|
146
|
+
const message = shouldBeExempted ? this.options.preserveSkippedFallbacks && areEqual ? `Preserving fallback for exempted token '${tokenKey}' (matches exemption '${exemptedPrefix}')` : `Skip modifying exempted token '${tokenKey}' (matches exemption '${exemptedPrefix}')` : normalizedFallbackValue === undefined ? `Fallback value could not be resolved` : `Values mismatched significantly`;
|
|
115
147
|
this.logError(message);
|
|
116
148
|
if (this.options.addEslintComments) {
|
|
117
149
|
addOrUpdateEslintIgnoreComment(this.j, tokenValue, fallbackValue, callPath);
|
|
@@ -211,6 +243,56 @@ export class TokenProcessor {
|
|
|
211
243
|
let objectName;
|
|
212
244
|
let propertyName;
|
|
213
245
|
let fallbackValue;
|
|
246
|
+
let resolvedImportDeclaration;
|
|
247
|
+
let resolvedLocalVarDeclaration;
|
|
248
|
+
|
|
249
|
+
// Function to get full member expression path as string
|
|
250
|
+
const getFullMemberPath = node => {
|
|
251
|
+
if (node.type === 'Identifier') {
|
|
252
|
+
return node.name;
|
|
253
|
+
} else if (node.type === 'MemberExpression') {
|
|
254
|
+
return `${getFullMemberPath(node.object)}.${node.property.type === 'Identifier' ? node.property.name : ''}`;
|
|
255
|
+
}
|
|
256
|
+
return '';
|
|
257
|
+
};
|
|
258
|
+
const fullMemberPath = getFullMemberPath(fallbackValueNode);
|
|
259
|
+
|
|
260
|
+
// Detect long member expression paths
|
|
261
|
+
const pathSegments = fullMemberPath.split('.');
|
|
262
|
+
if (pathSegments.length > 2) {
|
|
263
|
+
this.logVerbose(`Detected long member expression: ${chalk.yellow(fullMemberPath)}. Just resolving import or local variable declaration.`);
|
|
264
|
+
|
|
265
|
+
// Find the import statement or local variable for the top-level object
|
|
266
|
+
objectName = pathSegments[0];
|
|
267
|
+
|
|
268
|
+
// Check if it's a local variable
|
|
269
|
+
const localVarDeclaration = this.source.find(this.j.VariableDeclarator, {
|
|
270
|
+
id: {
|
|
271
|
+
name: objectName
|
|
272
|
+
}
|
|
273
|
+
}).at(0);
|
|
274
|
+
if (localVarDeclaration.size()) {
|
|
275
|
+
resolvedLocalVarDeclaration = localVarDeclaration.paths()[0];
|
|
276
|
+
this.logVerbose(`Resolved local variable declaration for: ${chalk.yellow(objectName)}`);
|
|
277
|
+
} else {
|
|
278
|
+
// Search for import declaration
|
|
279
|
+
const importDeclaration = this.source.find(this.j.ImportDeclaration).filter(this.createImportFilter(objectName)).at(0);
|
|
280
|
+
if (importDeclaration.size()) {
|
|
281
|
+
resolvedImportDeclaration = importDeclaration.paths()[0];
|
|
282
|
+
this.logVerbose(`Resolved import declaration for: ${chalk.yellow(objectName)}`);
|
|
283
|
+
} else {
|
|
284
|
+
this.logError(`Could not resolve import or local variable for: ${chalk.yellow(objectName)}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
rawFallbackValue: fullMemberPath,
|
|
289
|
+
fallbackValue: undefined,
|
|
290
|
+
resolvedImportDeclaration,
|
|
291
|
+
resolvedLocalVarDeclaration
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Existing logic for member expressions with shorter paths
|
|
214
296
|
if (fallbackValueNode.object.type === 'Identifier') {
|
|
215
297
|
objectName = fallbackValueNode.object.name;
|
|
216
298
|
}
|
|
@@ -230,7 +312,6 @@ export class TokenProcessor {
|
|
|
230
312
|
}
|
|
231
313
|
const rawFallbackValue = `${objectName}.${propertyName}`;
|
|
232
314
|
this.logVerbose(`Fallback is a member expression: ${chalk.yellow(rawFallbackValue)}, attempting to resolve...`);
|
|
233
|
-
let resolvedImportDeclaration;
|
|
234
315
|
|
|
235
316
|
// Find the import statement for the object
|
|
236
317
|
const importDeclaration = this.source.find(this.j.ImportDeclaration).filter(this.createImportFilter(objectName)).at(0);
|
|
@@ -253,22 +334,45 @@ export class TokenProcessor {
|
|
|
253
334
|
}
|
|
254
335
|
async processFallbackAsTemplateLiteral(fallbackValueNode) {
|
|
255
336
|
const expressions = fallbackValueNode.expressions;
|
|
337
|
+
const quasis = fallbackValueNode.quasis;
|
|
338
|
+
let resolvedImportDeclaration;
|
|
339
|
+
let resolvedLocalVarDeclaration;
|
|
256
340
|
let rawFallbackValue = '';
|
|
257
341
|
let fallbackValue;
|
|
258
|
-
const quasis = fallbackValueNode.quasis;
|
|
259
342
|
if (expressions.length !== 1 || quasis.length !== 2) {
|
|
260
343
|
this.logError(`Unsupported template literal structure`);
|
|
344
|
+
|
|
345
|
+
// Attempt to resolve any imports or local variables used in expressions
|
|
346
|
+
for (const expression of expressions) {
|
|
347
|
+
if (expression.type === 'Identifier') {
|
|
348
|
+
const result = await this.processFallbackAsIdentifier(expression);
|
|
349
|
+
if (result.resolvedImportDeclaration) {
|
|
350
|
+
resolvedImportDeclaration = result.resolvedImportDeclaration;
|
|
351
|
+
}
|
|
352
|
+
if (result.resolvedLocalVarDeclaration) {
|
|
353
|
+
resolvedLocalVarDeclaration = result.resolvedLocalVarDeclaration;
|
|
354
|
+
}
|
|
355
|
+
} else if (expression.type === 'MemberExpression') {
|
|
356
|
+
const result = await this.processFallbackAsMemberExpression(expression);
|
|
357
|
+
if (result.resolvedImportDeclaration) {
|
|
358
|
+
resolvedImportDeclaration = result.resolvedImportDeclaration;
|
|
359
|
+
}
|
|
360
|
+
if (result.resolvedLocalVarDeclaration) {
|
|
361
|
+
resolvedLocalVarDeclaration = result.resolvedLocalVarDeclaration;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
261
365
|
return {
|
|
262
366
|
rawFallbackValue,
|
|
263
367
|
fallbackValue,
|
|
264
|
-
resolvedImportDeclaration
|
|
265
|
-
resolvedLocalVarDeclaration
|
|
368
|
+
resolvedImportDeclaration,
|
|
369
|
+
resolvedLocalVarDeclaration
|
|
266
370
|
};
|
|
267
371
|
}
|
|
372
|
+
|
|
373
|
+
// Handle supported template literal structures as before
|
|
268
374
|
let exprValue;
|
|
269
375
|
const expression = expressions[0];
|
|
270
|
-
let resolvedImportDeclaration;
|
|
271
|
-
let resolvedLocalVarDeclaration;
|
|
272
376
|
if (expression.type === 'Identifier') {
|
|
273
377
|
const result = await this.processFallbackAsIdentifier(expression);
|
|
274
378
|
exprValue = result.fallbackValue;
|
package/dist/esm/main.js
CHANGED
|
@@ -128,7 +128,7 @@ var resolveTransform = /*#__PURE__*/function () {
|
|
|
128
128
|
}();
|
|
129
129
|
var runTransform = /*#__PURE__*/function () {
|
|
130
130
|
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(filePaths, transform, flags) {
|
|
131
|
-
var logger, codemodDirs, transformPath, args, jscodeshiftContent, jscodeshiftContentNew, transformModule;
|
|
131
|
+
var logger, codemodDirs, transformPath, ignorePatterns, ignoreArgs, args, jscodeshiftContent, jscodeshiftContentNew, transformModule;
|
|
132
132
|
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
133
133
|
while (1) switch (_context3.prev = _context3.next) {
|
|
134
134
|
case 0:
|
|
@@ -153,15 +153,20 @@ var runTransform = /*#__PURE__*/function () {
|
|
|
153
153
|
}
|
|
154
154
|
case 9:
|
|
155
155
|
logger.log(chalk.green("Transforming files matching these extensions '".concat(chalk.bold(flags.extensions), "'...")));
|
|
156
|
-
transformPath = getTransformPath(transform);
|
|
156
|
+
transformPath = getTransformPath(transform); // Split the ignorePattern by '|' and add each as a separate --ignore-pattern
|
|
157
|
+
ignorePatterns = flags.ignorePattern.split('|').filter(Boolean);
|
|
158
|
+
ignoreArgs = ignorePatterns.map(function (pattern) {
|
|
159
|
+
return "--ignore-pattern=".concat(pattern);
|
|
160
|
+
});
|
|
157
161
|
args = Object.keys(flags).reduce(function (acc, key) {
|
|
158
162
|
if (!['transform', 'parser', 'extensions', 'ignorePattern', 'logger', 'packages', 'sinceRef', 'preset', 'failOnError'].includes(key)) {
|
|
159
163
|
acc.unshift("--".concat(key, "=").concat(flags[key]));
|
|
160
164
|
}
|
|
161
165
|
return acc;
|
|
162
|
-
}, ["--transform=".concat(transformPath)
|
|
166
|
+
}, ["--transform=".concat(transformPath)].concat(_toConsumableArray(ignoreArgs), [// Spread the ignoreArgs array here
|
|
167
|
+
"--parser=".concat(flags.parser), "--extensions=".concat(flags.extensions),
|
|
163
168
|
// Limit CPUs to 8 to prevent issues when running on CI with a large amount of cpus
|
|
164
|
-
'--cpus=8']
|
|
169
|
+
'--cpus=8'], _toConsumableArray(codemodDirs)));
|
|
165
170
|
if (flags.failOnError) {
|
|
166
171
|
args.unshift('--fail-on-error');
|
|
167
172
|
}
|
|
@@ -179,24 +184,24 @@ var runTransform = /*#__PURE__*/function () {
|
|
|
179
184
|
console.warn("Error loading transform module: ".concat(transformPath, ". Skipping lifecycle hooks."));
|
|
180
185
|
}
|
|
181
186
|
if (!transformModule) {
|
|
182
|
-
_context3.next =
|
|
187
|
+
_context3.next = 22;
|
|
183
188
|
break;
|
|
184
189
|
}
|
|
185
|
-
_context3.next = 20;
|
|
186
|
-
return processLifecycleHook('beforeAll', transformModule, logger, transform, flags);
|
|
187
|
-
case 20:
|
|
188
190
|
_context3.next = 22;
|
|
191
|
+
return processLifecycleHook('beforeAll', transformModule, logger, transform, flags);
|
|
192
|
+
case 22:
|
|
193
|
+
_context3.next = 24;
|
|
189
194
|
return spawn(jscodeshift, args, {
|
|
190
195
|
stdio: 'inherit'
|
|
191
196
|
});
|
|
192
|
-
case
|
|
197
|
+
case 24:
|
|
193
198
|
if (!transformModule) {
|
|
194
|
-
_context3.next =
|
|
199
|
+
_context3.next = 27;
|
|
195
200
|
break;
|
|
196
201
|
}
|
|
197
|
-
_context3.next =
|
|
202
|
+
_context3.next = 27;
|
|
198
203
|
return processLifecycleHook('afterAll', transformModule, logger, transform, flags);
|
|
199
|
-
case
|
|
204
|
+
case 27:
|
|
200
205
|
case "end":
|
|
201
206
|
return _context3.stop();
|
|
202
207
|
}
|
|
@@ -302,7 +307,7 @@ var defaultFlags = {
|
|
|
302
307
|
ignorePattern: 'node_modules',
|
|
303
308
|
logger: console
|
|
304
309
|
};
|
|
305
|
-
function processLifecycleHook(_x9,
|
|
310
|
+
function processLifecycleHook(_x9, _x0, _x1, _x10, _x11) {
|
|
306
311
|
return _processLifecycleHook.apply(this, arguments);
|
|
307
312
|
}
|
|
308
313
|
function _processLifecycleHook() {
|
|
@@ -334,7 +339,7 @@ function _processLifecycleHook() {
|
|
|
334
339
|
}));
|
|
335
340
|
return _processLifecycleHook.apply(this, arguments);
|
|
336
341
|
}
|
|
337
|
-
export default function main(
|
|
342
|
+
export default function main(_x12, _x13) {
|
|
338
343
|
return _main.apply(this, arguments);
|
|
339
344
|
}
|
|
340
345
|
function _main() {
|
|
@@ -350,7 +355,7 @@ function _main() {
|
|
|
350
355
|
case 4:
|
|
351
356
|
_yield$parseArgs = _context6.sent;
|
|
352
357
|
packages = _yield$parseArgs.packages;
|
|
353
|
-
_process$env$_PACKAGE = "0.
|
|
358
|
+
_process$env$_PACKAGE = "0.28.1", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
|
|
354
359
|
logger.log(chalk.bgBlue(chalk.black("\uD83D\uDCDA Atlassian-Frontend codemod library @ ".concat(_PACKAGE_VERSION_, " \uD83D\uDCDA"))));
|
|
355
360
|
if (packages && packages.length > 0) {
|
|
356
361
|
logger.log(chalk.gray("Searching for codemods for newer versions of the following packages: ".concat(packages.map(function (pkg) {
|