@atlaskit/codemod-cli 0.27.1 → 0.27.3
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/cli.js +3 -3
- package/dist/cjs/filepath.js +4 -2
- package/dist/cjs/main.js +90 -38
- package/dist/cjs/presets/index.js +2 -1
- package/dist/cjs/presets/migrate-to-link/codemods/migrate-to-link.js +2 -2
- package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-split-imports.js +1 -1
- package/dist/cjs/presets/migrate-to-new-buttons/migrate-to-new-buttons.js +2 -2
- package/dist/cjs/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.js +1 -1
- package/dist/cjs/presets/remove-token-fallbacks/remove-token-fallbacks.js +225 -0
- package/dist/cjs/presets/remove-token-fallbacks/types.js +5 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/all-tokens.js +44 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/color-utils.js +93 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/get-team-info.js +51 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/normalize-values.js +113 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/remove-unused-imports.js +61 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/remove-unused-variables.js +37 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/reporter.js +310 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/token-processor.js +632 -0
- package/dist/cjs/presets/remove-token-fallbacks/utils/update-comments.js +58 -0
- package/dist/cjs/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.js +3 -3
- package/dist/cjs/sinceRef.js +2 -1
- package/dist/cjs/transforms.js +3 -1
- package/dist/cjs/types.js +2 -1
- package/dist/es2019/cli.js +3 -3
- package/dist/es2019/filepath.js +4 -2
- package/dist/es2019/main.js +30 -6
- package/dist/es2019/presets/index.js +2 -1
- package/dist/es2019/presets/migrate-to-link/codemods/migrate-to-link.js +2 -3
- package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-remove-unsafe-size.js +1 -1
- package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-split-imports.js +2 -2
- package/dist/es2019/presets/migrate-to-new-buttons/migrate-to-new-buttons.js +2 -2
- package/dist/es2019/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.js +1 -1
- package/dist/es2019/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.js +1 -1
- package/dist/es2019/presets/remove-token-fallbacks/remove-token-fallbacks.js +130 -0
- package/dist/es2019/presets/remove-token-fallbacks/types.js +1 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/all-tokens.js +30 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/color-utils.js +84 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/get-team-info.js +22 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/normalize-values.js +104 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/remove-unused-imports.js +51 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/remove-unused-variables.js +31 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/reporter.js +118 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/token-processor.js +377 -0
- package/dist/es2019/presets/remove-token-fallbacks/utils/update-comments.js +46 -0
- package/dist/es2019/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.js +1 -1
- package/dist/es2019/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.js +3 -3
- package/dist/es2019/sinceRef.js +2 -1
- package/dist/es2019/transforms.js +3 -1
- package/dist/es2019/types.js +2 -1
- package/dist/esm/cli.js +3 -3
- package/dist/esm/filepath.js +4 -2
- package/dist/esm/main.js +91 -39
- package/dist/esm/presets/index.js +2 -1
- package/dist/esm/presets/migrate-to-link/codemods/migrate-to-link.js +2 -3
- package/dist/esm/presets/migrate-to-new-buttons/codemods/next-remove-unsafe-size.js +1 -1
- package/dist/esm/presets/migrate-to-new-buttons/codemods/next-split-imports.js +2 -2
- package/dist/esm/presets/migrate-to-new-buttons/migrate-to-new-buttons.js +2 -2
- package/dist/esm/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.js +1 -1
- package/dist/esm/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.js +1 -1
- package/dist/esm/presets/remove-token-fallbacks/remove-token-fallbacks.js +215 -0
- package/dist/esm/presets/remove-token-fallbacks/types.js +1 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/all-tokens.js +38 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/color-utils.js +86 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/get-team-info.js +44 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/normalize-values.js +107 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/remove-unused-imports.js +55 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/remove-unused-variables.js +31 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/reporter.js +302 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/token-processor.js +625 -0
- package/dist/esm/presets/remove-token-fallbacks/utils/update-comments.js +51 -0
- package/dist/esm/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.js +1 -1
- package/dist/esm/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.js +3 -3
- package/dist/esm/sinceRef.js +2 -1
- package/dist/esm/transforms.js +3 -1
- package/dist/esm/types.js +2 -1
- package/dist/types/filepath.d.ts +3 -1
- package/dist/types/main.d.ts +1 -1
- package/dist/types/presets/index.d.ts +1 -0
- package/dist/types/presets/migrate-to-new-buttons/utils/import-types-from-new-entry-point.d.ts +1 -1
- package/dist/types/presets/migrate-to-new-buttons/utils/move-icon-value-from-link-button-to-link-children.d.ts +1 -1
- package/dist/types/presets/remove-token-fallbacks/remove-token-fallbacks.d.ts +29 -0
- package/dist/types/presets/remove-token-fallbacks/types.d.ts +39 -0
- package/dist/types/presets/remove-token-fallbacks/utils/all-tokens.d.ts +1 -0
- package/dist/types/presets/remove-token-fallbacks/utils/color-utils.d.ts +3 -0
- package/dist/types/presets/remove-token-fallbacks/utils/get-team-info.d.ts +8 -0
- package/dist/types/presets/remove-token-fallbacks/utils/normalize-values.d.ts +8 -0
- package/dist/types/presets/remove-token-fallbacks/utils/remove-unused-imports.d.ts +2 -0
- package/dist/types/presets/remove-token-fallbacks/utils/remove-unused-variables.d.ts +2 -0
- package/dist/types/presets/remove-token-fallbacks/utils/reporter.d.ts +4 -0
- package/dist/types/presets/remove-token-fallbacks/utils/token-processor.d.ts +30 -0
- package/dist/types/presets/remove-token-fallbacks/utils/update-comments.d.ts +2 -0
- package/dist/types/presets/styled-to-emotion/styled-to-emotion.d.ts +1 -1
- package/dist/types/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.d.ts +1 -1
- package/dist/types/sinceRef.d.ts +2 -1
- package/dist/types/transforms.d.ts +3 -1
- package/dist/types/types.d.ts +3 -2
- package/dist/types-ts4.5/filepath.d.ts +3 -1
- package/dist/types-ts4.5/main.d.ts +1 -1
- package/dist/types-ts4.5/presets/index.d.ts +1 -0
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/import-types-from-new-entry-point.d.ts +1 -1
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/move-icon-value-from-link-button-to-link-children.d.ts +1 -1
- package/dist/types-ts4.5/presets/remove-token-fallbacks/remove-token-fallbacks.d.ts +29 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/types.d.ts +39 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/all-tokens.d.ts +1 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/color-utils.d.ts +3 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/get-team-info.d.ts +8 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/normalize-values.d.ts +8 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/remove-unused-imports.d.ts +2 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/remove-unused-variables.d.ts +2 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/reporter.d.ts +4 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/token-processor.d.ts +30 -0
- package/dist/types-ts4.5/presets/remove-token-fallbacks/utils/update-comments.d.ts +2 -0
- package/dist/types-ts4.5/presets/styled-to-emotion/styled-to-emotion.d.ts +1 -1
- package/dist/types-ts4.5/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.d.ts +1 -1
- package/dist/types-ts4.5/sinceRef.d.ts +2 -1
- package/dist/types-ts4.5/transforms.d.ts +3 -1
- package/dist/types-ts4.5/types.d.ts +3 -2
- package/package.json +8 -3
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { colorToHex, compareHex, isValidColor } from './color-utils';
|
|
3
|
+
|
|
4
|
+
// so far allowing to remove only exact matches in values. Can be increased to auto-remove fallbacks with similar values
|
|
5
|
+
const ACCEPTABLE_COLOR_DIFFERENCE = 0;
|
|
6
|
+
const ACCEPTABLE_SPACE_DIFFERENCE = 0;
|
|
7
|
+
const ACCEPTABLE_NUMERIC_DIFFERENCE = 0;
|
|
8
|
+
export function normalizeValues(tokenKey, tokenValue, fallbackValue) {
|
|
9
|
+
let tokenLogValue;
|
|
10
|
+
let fallbackLogValue;
|
|
11
|
+
let normalizedTokenValue = tokenValue;
|
|
12
|
+
let normalizedFallbackValue = fallbackValue;
|
|
13
|
+
const lowerCaseTokenKey = tokenKey === null || tokenKey === void 0 ? void 0 : tokenKey.toLowerCase();
|
|
14
|
+
let difference;
|
|
15
|
+
let isAcceptableDifference;
|
|
16
|
+
if (lowerCaseTokenKey.startsWith('color') || lowerCaseTokenKey.startsWith('elevation')) {
|
|
17
|
+
if (tokenValue && isValidColor(tokenValue)) {
|
|
18
|
+
const normalizedHex = colorToHex(tokenValue);
|
|
19
|
+
tokenLogValue = chalk.bgHex(normalizedHex)(tokenValue);
|
|
20
|
+
normalizedTokenValue = normalizedHex;
|
|
21
|
+
}
|
|
22
|
+
if (fallbackValue && isValidColor(fallbackValue)) {
|
|
23
|
+
const normalizedHex = colorToHex(fallbackValue);
|
|
24
|
+
fallbackLogValue = chalk.bgHex(normalizedHex)(fallbackValue);
|
|
25
|
+
normalizedFallbackValue = normalizedHex;
|
|
26
|
+
}
|
|
27
|
+
if (normalizedTokenValue && normalizedFallbackValue) {
|
|
28
|
+
difference = compareHex(normalizedTokenValue, normalizedFallbackValue);
|
|
29
|
+
isAcceptableDifference = difference <= ACCEPTABLE_COLOR_DIFFERENCE;
|
|
30
|
+
}
|
|
31
|
+
} else if (lowerCaseTokenKey.startsWith('space')) {
|
|
32
|
+
const tokenValueInPx = tokenValue ? convertToPx(tokenValue) : undefined;
|
|
33
|
+
const fallbackValueInPx = fallbackValue ? convertToPx(fallbackValue) : undefined;
|
|
34
|
+
if (tokenValueInPx !== undefined && fallbackValueInPx !== undefined) {
|
|
35
|
+
const maxVal = Math.max(tokenValueInPx, fallbackValueInPx);
|
|
36
|
+
difference = Math.abs(tokenValueInPx - fallbackValueInPx) / maxVal * 100;
|
|
37
|
+
isAcceptableDifference = difference <= ACCEPTABLE_SPACE_DIFFERENCE;
|
|
38
|
+
}
|
|
39
|
+
// Log the normalized values
|
|
40
|
+
normalizedTokenValue = tokenValue;
|
|
41
|
+
normalizedFallbackValue = fallbackValue;
|
|
42
|
+
tokenLogValue = tokenValue;
|
|
43
|
+
fallbackLogValue = fallbackValue;
|
|
44
|
+
} else {
|
|
45
|
+
// Handle other numeric comparisons
|
|
46
|
+
const tokenValueNumber = parseFloat(tokenValue !== null && tokenValue !== void 0 ? tokenValue : '');
|
|
47
|
+
const fallbackValueNumber = parseFloat(fallbackValue !== null && fallbackValue !== void 0 ? fallbackValue : '');
|
|
48
|
+
if (!isNaN(tokenValueNumber) && !isNaN(fallbackValueNumber)) {
|
|
49
|
+
const maxVal = Math.max(tokenValueNumber, fallbackValueNumber);
|
|
50
|
+
difference = Math.abs(tokenValueNumber - fallbackValueNumber) / maxVal * 100;
|
|
51
|
+
isAcceptableDifference = difference <= ACCEPTABLE_NUMERIC_DIFFERENCE;
|
|
52
|
+
}
|
|
53
|
+
// Log the normalized values
|
|
54
|
+
normalizedTokenValue = tokenValue;
|
|
55
|
+
normalizedFallbackValue = fallbackValue;
|
|
56
|
+
tokenLogValue = tokenValue;
|
|
57
|
+
fallbackLogValue = fallbackValue;
|
|
58
|
+
}
|
|
59
|
+
if (tokenLogValue === undefined) {
|
|
60
|
+
tokenLogValue = chalk.magenta(tokenValue || '');
|
|
61
|
+
}
|
|
62
|
+
if (fallbackLogValue === undefined) {
|
|
63
|
+
fallbackLogValue = chalk.yellow(fallbackValue || '');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
difference,
|
|
67
|
+
isAcceptableDifference,
|
|
68
|
+
tokenLogValue,
|
|
69
|
+
fallbackLogValue,
|
|
70
|
+
normalizedTokenValue,
|
|
71
|
+
normalizedFallbackValue
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function convertToPx(value) {
|
|
75
|
+
// If the value is a number, return it directly
|
|
76
|
+
if (typeof value === 'number') {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
// Check if the string is a plain number (without units)
|
|
80
|
+
const plainNumberRegex = /^-?\d+(\.\d+)?$/;
|
|
81
|
+
if (plainNumberRegex.test(value)) {
|
|
82
|
+
return parseFloat(value);
|
|
83
|
+
}
|
|
84
|
+
// Regular expression to match CSS units
|
|
85
|
+
const unitRegex = /^(-?\d+(\.\d+)?)(px|rem|em|%)$/;
|
|
86
|
+
const match = value.match(unitRegex);
|
|
87
|
+
if (!match) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const [, num,, unit] = match;
|
|
91
|
+
const numericValue = parseFloat(num);
|
|
92
|
+
switch (unit) {
|
|
93
|
+
case 'px':
|
|
94
|
+
return numericValue;
|
|
95
|
+
case 'rem':
|
|
96
|
+
return numericValue * 16;
|
|
97
|
+
// Assuming 1rem = 16px
|
|
98
|
+
case 'em':
|
|
99
|
+
return numericValue * 16;
|
|
100
|
+
// Assuming 1em = 16px
|
|
101
|
+
default:
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function removeUnusedImports(importDeclarations, j) {
|
|
2
|
+
const removeIfUnused = (importSpecifier, importDeclaration) => {
|
|
3
|
+
var _importSpecifier$valu;
|
|
4
|
+
const varName = (_importSpecifier$valu = importSpecifier.value.local) === null || _importSpecifier$valu === void 0 ? void 0 : _importSpecifier$valu.name;
|
|
5
|
+
if (varName === 'React' || varName === 'jsx') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const isUsedInScopes = () => {
|
|
9
|
+
return j(importDeclaration).closestScope().find(j.Identifier, {
|
|
10
|
+
name: varName
|
|
11
|
+
}).filter(p => {
|
|
12
|
+
var _importSpecifier$valu2;
|
|
13
|
+
if (p.value.start === ((_importSpecifier$valu2 = importSpecifier.value.local) === null || _importSpecifier$valu2 === void 0 ? void 0 : _importSpecifier$valu2.start)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (p.parentPath.value.type === 'Property' && p.name === 'key') {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (p.name === 'property') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}).size() > 0;
|
|
24
|
+
};
|
|
25
|
+
if (!isUsedInScopes()) {
|
|
26
|
+
j(importSpecifier).remove();
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
31
|
+
const removeUnusedDefaultImport = importDeclaration => {
|
|
32
|
+
return j(importDeclaration).find(j.ImportDefaultSpecifier).filter(s => removeIfUnused(s, importDeclaration)).size() > 0;
|
|
33
|
+
};
|
|
34
|
+
const removeUnusedNonDefaultImports = importDeclaration => {
|
|
35
|
+
return j(importDeclaration).find(j.ImportSpecifier).filter(s => removeIfUnused(s, importDeclaration)).size() > 0;
|
|
36
|
+
};
|
|
37
|
+
const processImportDeclaration = importDeclaration => {
|
|
38
|
+
var _importDeclaration$va, _importDeclaration$va2;
|
|
39
|
+
if (((_importDeclaration$va = importDeclaration.value.specifiers) === null || _importDeclaration$va === void 0 ? void 0 : _importDeclaration$va.length) === 0) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const hadUnusedDefaultImport = removeUnusedDefaultImport(importDeclaration);
|
|
43
|
+
const hadUnusedNonDefaultImports = removeUnusedNonDefaultImports(importDeclaration);
|
|
44
|
+
if (((_importDeclaration$va2 = importDeclaration.value.specifiers) === null || _importDeclaration$va2 === void 0 ? void 0 : _importDeclaration$va2.length) === 0) {
|
|
45
|
+
j(importDeclaration).remove();
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return hadUnusedDefaultImport || hadUnusedNonDefaultImports;
|
|
49
|
+
};
|
|
50
|
+
importDeclarations.forEach(processImportDeclaration);
|
|
51
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function removeUnusedVariables(variableDeclarations, j) {
|
|
2
|
+
const removeIfUnused = varDeclarator => {
|
|
3
|
+
var _varDeclarator$value;
|
|
4
|
+
if (((_varDeclarator$value = varDeclarator.value) === null || _varDeclarator$value === void 0 ? void 0 : _varDeclarator$value.id.type) !== 'Identifier') {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const varName = varDeclarator.value.id.name;
|
|
8
|
+
const isUsedInScopes = () => {
|
|
9
|
+
return j(varDeclarator).closestScope().find(j.Identifier, {
|
|
10
|
+
name: varName
|
|
11
|
+
}).filter(p => {
|
|
12
|
+
if (p.value.start === varDeclarator.value.id.start) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (p.parentPath.value.type === 'Property' && p.name === 'key') {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (p.name === 'property') {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}).size() > 0;
|
|
23
|
+
};
|
|
24
|
+
if (!isUsedInScopes()) {
|
|
25
|
+
j(varDeclarator).remove();
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
variableDeclarations.forEach(removeIfUnused);
|
|
31
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
async function writeToCsv(filePath, data) {
|
|
6
|
+
await fs.writeFile(filePath, data.join('\n'), 'utf-8');
|
|
7
|
+
}
|
|
8
|
+
async function readCsv(filePath) {
|
|
9
|
+
const data = await fs.readFile(filePath, 'utf-8');
|
|
10
|
+
return data.split('\n').filter(line => line.trim() !== '');
|
|
11
|
+
}
|
|
12
|
+
function escapeCsvValue(value) {
|
|
13
|
+
if (!value) {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
if (value.includes('"')) {
|
|
17
|
+
// Escape double quotes by doubling them
|
|
18
|
+
value = value.replace(/"/g, '""');
|
|
19
|
+
}
|
|
20
|
+
if (value.includes(',') || value.includes('"') || value.includes('\n')) {
|
|
21
|
+
// Surround the value with double quotes if it contains a comma, double quotes, or newlines
|
|
22
|
+
value = `"${value}"`;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
export async function clearFolder(reportFolder) {
|
|
27
|
+
console.log('Clearing report folder:', reportFolder);
|
|
28
|
+
const filesToDelete = await fs.readdir(reportFolder);
|
|
29
|
+
for (const file of filesToDelete) {
|
|
30
|
+
const filePath = path.join(reportFolder, file);
|
|
31
|
+
await fs.unlink(filePath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function saveFilePaths(reportFolder, files) {
|
|
35
|
+
const filesTxtPath = path.join(reportFolder, 'files.txt');
|
|
36
|
+
await fs.writeFile(filesTxtPath, Array.from(files).map(filePath => `"${filePath}"`).join(' '), 'utf-8');
|
|
37
|
+
}
|
|
38
|
+
export async function combineReports(reportFolder) {
|
|
39
|
+
console.log('Combining reports in folder:', reportFolder);
|
|
40
|
+
const files = await fs.readdir(reportFolder);
|
|
41
|
+
let totalReplaced = 0;
|
|
42
|
+
let totalNotReplaced = 0;
|
|
43
|
+
const combinedReplacements = [];
|
|
44
|
+
const combinedNonReplacements = [];
|
|
45
|
+
const affectedPaths = new Set();
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
const filePath = path.join(reportFolder, file);
|
|
48
|
+
if (file.endsWith('_success.csv')) {
|
|
49
|
+
const replacements = await readCsv(filePath);
|
|
50
|
+
const codeFilePaths = replacements.map(x => x.split(',')[2]);
|
|
51
|
+
for (const codeFilePath of codeFilePaths) {
|
|
52
|
+
affectedPaths.add(codeFilePath);
|
|
53
|
+
}
|
|
54
|
+
totalReplaced += replacements.length;
|
|
55
|
+
combinedReplacements.push(...replacements);
|
|
56
|
+
} else if (file.endsWith('_failed.csv')) {
|
|
57
|
+
const nonReplacements = await readCsv(filePath);
|
|
58
|
+
totalNotReplaced += nonReplacements.length;
|
|
59
|
+
combinedNonReplacements.push(...nonReplacements);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const totalTokens = totalReplaced + totalNotReplaced;
|
|
63
|
+
const percentageReplaced = totalTokens > 0 ? totalReplaced / totalTokens * 100 : 0;
|
|
64
|
+
await clearFolder(reportFolder);
|
|
65
|
+
|
|
66
|
+
// Write combined summary as JSON
|
|
67
|
+
const combinedSummaryPath = path.join(reportFolder, 'summary.json');
|
|
68
|
+
const summaryData = {
|
|
69
|
+
totalReplaced,
|
|
70
|
+
totalNotReplaced,
|
|
71
|
+
percentageReplaced
|
|
72
|
+
};
|
|
73
|
+
await fs.writeFile(combinedSummaryPath, JSON.stringify(summaryData, null, 2), 'utf-8');
|
|
74
|
+
|
|
75
|
+
// Sort the combined arrays
|
|
76
|
+
const sortCsvLines = lines => {
|
|
77
|
+
return lines.sort((a, b) => {
|
|
78
|
+
const aCols = a.split(',');
|
|
79
|
+
const bCols = b.split(',');
|
|
80
|
+
for (let i = 0; i < 4; i++) {
|
|
81
|
+
const comparison = aCols[i].localeCompare(bCols[i]);
|
|
82
|
+
if (comparison !== 0) {
|
|
83
|
+
return comparison;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return 0;
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const sortedReplacements = sortCsvLines(combinedReplacements);
|
|
90
|
+
const sortedNonReplacements = sortCsvLines(combinedNonReplacements);
|
|
91
|
+
|
|
92
|
+
// Write combined replacements
|
|
93
|
+
const combinedReplacementsPath = path.join(reportFolder, 'success.csv');
|
|
94
|
+
const header = 'Team,Package,File,Line Number,Raw Token Key,Raw Fallback Value,Resolved Token Value,Resolved Fallback Value,Difference %';
|
|
95
|
+
await fs.writeFile(combinedReplacementsPath, [header, ...sortedReplacements].join('\n'), 'utf-8');
|
|
96
|
+
|
|
97
|
+
// Write combined non-replacements
|
|
98
|
+
const combinedNonReplacementsPath = path.join(reportFolder, 'failed.csv');
|
|
99
|
+
await fs.writeFile(combinedNonReplacementsPath, [header, ...sortedNonReplacements].join('\n'), 'utf-8');
|
|
100
|
+
// Extract unique file paths
|
|
101
|
+
await saveFilePaths(reportFolder, affectedPaths);
|
|
102
|
+
}
|
|
103
|
+
function prepareCsvData(items) {
|
|
104
|
+
return items.map(item => {
|
|
105
|
+
var _item$difference$toFi, _item$difference;
|
|
106
|
+
return [escapeCsvValue(item.teamInfo.teamName), escapeCsvValue(item.teamInfo.packageName), escapeCsvValue(item.filePath), escapeCsvValue(String(item.lineNumber)), escapeCsvValue(item.tokenKey), escapeCsvValue(item.rawFallbackValue), escapeCsvValue(item.resolvedTokenValue), escapeCsvValue(item.resolvedFallbackValue), escapeCsvValue((_item$difference$toFi = (_item$difference = item.difference) === null || _item$difference === void 0 ? void 0 : _item$difference.toFixed(1)) !== null && _item$difference$toFi !== void 0 ? _item$difference$toFi : '')].join(',');
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
export async function writeReports(details, reportFolder) {
|
|
110
|
+
const replacementsFilePath = path.join(reportFolder, `${uuidv4()}_success.csv`);
|
|
111
|
+
const nonReplacementsFilePath = path.join(reportFolder, `${uuidv4()}_failed.csv`);
|
|
112
|
+
await fs.mkdir(reportFolder, {
|
|
113
|
+
recursive: true
|
|
114
|
+
});
|
|
115
|
+
const replacementData = prepareCsvData(details.replaced);
|
|
116
|
+
const nonReplacementData = prepareCsvData(details.notReplaced);
|
|
117
|
+
await Promise.all([writeToCsv(replacementsFilePath, replacementData), writeToCsv(nonReplacementsFilePath, nonReplacementData)]);
|
|
118
|
+
}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { normalizeValues } from './normalize-values';
|
|
7
|
+
import { addOrUpdateEslintIgnoreComment } from './update-comments';
|
|
8
|
+
export class TokenProcessor {
|
|
9
|
+
constructor(j, options, fileInfo, source, rootDir, details, tokenMap, teamInfo) {
|
|
10
|
+
_defineProperty(this, "logMessages", []);
|
|
11
|
+
_defineProperty(this, "possibleExtensions", ['.ts', '.tsx', '.js', '.jsx']);
|
|
12
|
+
this.j = j;
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.fileInfo = fileInfo;
|
|
15
|
+
this.source = source;
|
|
16
|
+
this.rootDir = rootDir;
|
|
17
|
+
this.details = details;
|
|
18
|
+
this.tokenMap = tokenMap;
|
|
19
|
+
this.teamInfo = teamInfo;
|
|
20
|
+
}
|
|
21
|
+
async processAndLogSingleToken(callPath) {
|
|
22
|
+
var _callPath$node$loc;
|
|
23
|
+
const line = (_callPath$node$loc = callPath.node.loc) === null || _callPath$node$loc === void 0 ? void 0 : _callPath$node$loc.start.line;
|
|
24
|
+
const {
|
|
25
|
+
shouldLog,
|
|
26
|
+
...rest
|
|
27
|
+
} = await this.processSingleToken(callPath);
|
|
28
|
+
if (this.options.silent || !shouldLog) {
|
|
29
|
+
return rest;
|
|
30
|
+
}
|
|
31
|
+
const coloredPath = chalk.blue(this.fileInfo.path);
|
|
32
|
+
const coloredLine = line ? `: ${chalk.green(line)}` : '';
|
|
33
|
+
console.log(`${coloredPath}${coloredLine}: ${this.logMessages.join(' | ')}
|
|
34
|
+
----------------------------------------`);
|
|
35
|
+
return rest;
|
|
36
|
+
}
|
|
37
|
+
logVerbose(message) {
|
|
38
|
+
if (this.options.verbose) {
|
|
39
|
+
this.log(message);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
log(message) {
|
|
43
|
+
this.logMessages.push(message);
|
|
44
|
+
}
|
|
45
|
+
logError(message) {
|
|
46
|
+
this.log(chalk.red(message));
|
|
47
|
+
}
|
|
48
|
+
async processSingleToken(callPath) {
|
|
49
|
+
var _callPath$node$loc2;
|
|
50
|
+
const args = callPath.node.arguments;
|
|
51
|
+
const line = (_callPath$node$loc2 = callPath.node.loc) === null || _callPath$node$loc2 === void 0 ? void 0 : _callPath$node$loc2.start.line;
|
|
52
|
+
if (args.length < 2) {
|
|
53
|
+
this.logVerbose(chalk.yellow('Skipped token call without fallback'));
|
|
54
|
+
return {
|
|
55
|
+
shouldLog: false,
|
|
56
|
+
fallbackRemoved: false,
|
|
57
|
+
resolvedImportDeclaration: undefined,
|
|
58
|
+
resolvedLocalVarDeclaration: undefined
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const tokenKey = this.getTokenKey(args[0]);
|
|
62
|
+
if (!tokenKey) {
|
|
63
|
+
return {
|
|
64
|
+
shouldLog: true,
|
|
65
|
+
fallbackRemoved: false,
|
|
66
|
+
resolvedImportDeclaration: undefined,
|
|
67
|
+
resolvedLocalVarDeclaration: undefined
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const isSkipped = tokenKey.startsWith('elevation.shadow') || tokenKey.startsWith('font.body') || tokenKey.startsWith('font.heading');
|
|
71
|
+
const tokenValue = isSkipped ? '' : this.tokenMap[tokenKey];
|
|
72
|
+
this.logVerbose(`Token value from tokenMap: ${chalk.magenta(tokenValue)} for key: ${chalk.yellow(tokenKey)}`);
|
|
73
|
+
const {
|
|
74
|
+
rawFallbackValue,
|
|
75
|
+
fallbackValue,
|
|
76
|
+
resolvedImportDeclaration,
|
|
77
|
+
resolvedLocalVarDeclaration
|
|
78
|
+
} = isSkipped ? {
|
|
79
|
+
rawFallbackValue: 'N/A',
|
|
80
|
+
fallbackValue: undefined,
|
|
81
|
+
resolvedImportDeclaration: undefined,
|
|
82
|
+
resolvedLocalVarDeclaration: undefined
|
|
83
|
+
} : await this.getFallbackValue(args[1]);
|
|
84
|
+
const {
|
|
85
|
+
difference,
|
|
86
|
+
isAcceptableDifference,
|
|
87
|
+
tokenLogValue,
|
|
88
|
+
fallbackLogValue,
|
|
89
|
+
normalizedTokenValue,
|
|
90
|
+
normalizedFallbackValue
|
|
91
|
+
} = normalizeValues(tokenKey, tokenValue, fallbackValue);
|
|
92
|
+
const areEqual = normalizedTokenValue === normalizedFallbackValue;
|
|
93
|
+
const logData = {
|
|
94
|
+
teamInfo: this.teamInfo,
|
|
95
|
+
filePath: this.fileInfo.path,
|
|
96
|
+
lineNumber: line || -1,
|
|
97
|
+
tokenKey,
|
|
98
|
+
rawFallbackValue,
|
|
99
|
+
resolvedTokenValue: tokenValue,
|
|
100
|
+
resolvedFallbackValue: fallbackValue !== null && fallbackValue !== void 0 ? fallbackValue : '',
|
|
101
|
+
difference
|
|
102
|
+
};
|
|
103
|
+
let fallbackRemoved = false;
|
|
104
|
+
let importDeclaration;
|
|
105
|
+
let localVarDeclaration;
|
|
106
|
+
if (areEqual || isAcceptableDifference || this.options.forceUpdate) {
|
|
107
|
+
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
|
+
args.pop();
|
|
109
|
+
this.details.replaced.push(logData);
|
|
110
|
+
fallbackRemoved = true;
|
|
111
|
+
importDeclaration = resolvedImportDeclaration;
|
|
112
|
+
localVarDeclaration = resolvedLocalVarDeclaration;
|
|
113
|
+
} else {
|
|
114
|
+
const message = normalizedFallbackValue === undefined ? `Fallback value could not be resolved` : `Values mismatched significantly`;
|
|
115
|
+
this.logError(message);
|
|
116
|
+
if (this.options.addEslintComments) {
|
|
117
|
+
addOrUpdateEslintIgnoreComment(this.j, tokenValue, fallbackValue, callPath);
|
|
118
|
+
}
|
|
119
|
+
this.details.notReplaced.push(logData);
|
|
120
|
+
}
|
|
121
|
+
this.log(`Token: ${chalk.yellow(tokenKey)}, Raw fallback: ${chalk.yellow(rawFallbackValue)}, Resolved token value: ${tokenLogValue}, Resolved fallback value: ${fallbackLogValue}`);
|
|
122
|
+
return {
|
|
123
|
+
shouldLog: true,
|
|
124
|
+
fallbackRemoved,
|
|
125
|
+
resolvedImportDeclaration: importDeclaration,
|
|
126
|
+
resolvedLocalVarDeclaration: localVarDeclaration
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
getTokenKey(arg) {
|
|
130
|
+
if (arg.type === 'StringLiteral') {
|
|
131
|
+
const tokenKey = arg.value;
|
|
132
|
+
this.logVerbose(`Determined token key as literal: ${chalk.yellow(tokenKey)}`);
|
|
133
|
+
return tokenKey;
|
|
134
|
+
} else {
|
|
135
|
+
this.logError(`The first argument of token function is not a string literal`);
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async getFallbackValue(fallbackValueNode) {
|
|
140
|
+
switch (fallbackValueNode.type) {
|
|
141
|
+
case 'StringLiteral':
|
|
142
|
+
return this.processFallbackAsStringLiteral(fallbackValueNode);
|
|
143
|
+
case 'Identifier':
|
|
144
|
+
return this.processFallbackAsIdentifier(fallbackValueNode);
|
|
145
|
+
case 'MemberExpression':
|
|
146
|
+
return this.processFallbackAsMemberExpression(fallbackValueNode);
|
|
147
|
+
case 'TemplateLiteral':
|
|
148
|
+
return this.processFallbackAsTemplateLiteral(fallbackValueNode);
|
|
149
|
+
default:
|
|
150
|
+
return {
|
|
151
|
+
fallbackValue: undefined,
|
|
152
|
+
rawFallbackValue: '',
|
|
153
|
+
resolvedImportDeclaration: undefined,
|
|
154
|
+
resolvedLocalVarDeclaration: undefined
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
processFallbackAsStringLiteral(fallbackValueNode) {
|
|
159
|
+
const fallbackValue = fallbackValueNode.value;
|
|
160
|
+
this.logVerbose(`Fallback value is a literal: ${chalk.yellow(fallbackValue)}`);
|
|
161
|
+
return {
|
|
162
|
+
fallbackValue,
|
|
163
|
+
rawFallbackValue: fallbackValue,
|
|
164
|
+
resolvedImportDeclaration: undefined,
|
|
165
|
+
resolvedLocalVarDeclaration: undefined
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async processFallbackAsIdentifier(fallbackValueNode) {
|
|
169
|
+
const variableName = fallbackValueNode.name;
|
|
170
|
+
const variableNameForLog = `${chalk.yellow(variableName)}`;
|
|
171
|
+
let fallbackValue;
|
|
172
|
+
this.logVerbose(`Fallback is an identifier: ${chalk.yellow(variableName)}, attempting to resolve...`);
|
|
173
|
+
|
|
174
|
+
// Check for local variable declaration
|
|
175
|
+
const localVarDeclaration = this.source.find(this.j.VariableDeclarator, {
|
|
176
|
+
id: {
|
|
177
|
+
name: variableName
|
|
178
|
+
}
|
|
179
|
+
}).at(0);
|
|
180
|
+
let resolvedImportDeclaration;
|
|
181
|
+
let resolvedLocalVarDeclaration;
|
|
182
|
+
if (localVarDeclaration.size()) {
|
|
183
|
+
const init = localVarDeclaration.get().value.init;
|
|
184
|
+
if (init.type === 'Literal' || init.type === 'StringLiteral') {
|
|
185
|
+
fallbackValue = init.value;
|
|
186
|
+
resolvedLocalVarDeclaration = localVarDeclaration.paths()[0];
|
|
187
|
+
this.logVerbose(`Resolved fallback value from local variable: ${chalk.yellow(fallbackValue)} for identifier: ${variableNameForLog}`);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
// Check for named import
|
|
191
|
+
const importDeclaration = this.source.find(this.j.ImportDeclaration).filter(this.createImportFilter(variableName)).at(0);
|
|
192
|
+
if (importDeclaration.size()) {
|
|
193
|
+
const importSource = importDeclaration.get().value.source.value;
|
|
194
|
+
fallbackValue = await this.resolveValueFromImport(this.rootDir, importSource, undefined, variableName);
|
|
195
|
+
if (fallbackValue !== undefined) {
|
|
196
|
+
this.logVerbose(`Resolved fallback value from import: ${chalk.yellow(fallbackValue)} for identifier: ${variableNameForLog}`);
|
|
197
|
+
resolvedImportDeclaration = importDeclaration.paths()[0];
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
this.logVerbose(chalk.red(`Could not resolve fallback value for identifier: ${variableNameForLog}: it's neither a local variable nor an import`));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
rawFallbackValue: variableName,
|
|
205
|
+
fallbackValue,
|
|
206
|
+
resolvedImportDeclaration,
|
|
207
|
+
resolvedLocalVarDeclaration
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
async processFallbackAsMemberExpression(fallbackValueNode) {
|
|
211
|
+
let objectName;
|
|
212
|
+
let propertyName;
|
|
213
|
+
let fallbackValue;
|
|
214
|
+
if (fallbackValueNode.object.type === 'Identifier') {
|
|
215
|
+
objectName = fallbackValueNode.object.name;
|
|
216
|
+
}
|
|
217
|
+
if (fallbackValueNode.property.type === 'Identifier') {
|
|
218
|
+
propertyName = fallbackValueNode.property.name;
|
|
219
|
+
} else if (fallbackValueNode.property.type === 'Literal' && typeof fallbackValueNode.property.value === 'string') {
|
|
220
|
+
propertyName = fallbackValueNode.property.value;
|
|
221
|
+
}
|
|
222
|
+
if (!objectName || !propertyName) {
|
|
223
|
+
this.logError(`Could not determine object and property names from member expression: ${chalk.yellow(fallbackValueNode)}`);
|
|
224
|
+
return {
|
|
225
|
+
rawFallbackValue: '',
|
|
226
|
+
fallbackValue,
|
|
227
|
+
resolvedImportDeclaration: undefined,
|
|
228
|
+
resolvedLocalVarDeclaration: undefined
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const rawFallbackValue = `${objectName}.${propertyName}`;
|
|
232
|
+
this.logVerbose(`Fallback is a member expression: ${chalk.yellow(rawFallbackValue)}, attempting to resolve...`);
|
|
233
|
+
let resolvedImportDeclaration;
|
|
234
|
+
|
|
235
|
+
// Find the import statement for the object
|
|
236
|
+
const importDeclaration = this.source.find(this.j.ImportDeclaration).filter(this.createImportFilter(objectName)).at(0);
|
|
237
|
+
if (importDeclaration.size()) {
|
|
238
|
+
const importSource = importDeclaration.get().value.source.value;
|
|
239
|
+
fallbackValue = await this.resolveValueFromImport(this.rootDir, importSource, objectName, propertyName);
|
|
240
|
+
if (fallbackValue !== undefined) {
|
|
241
|
+
resolvedImportDeclaration = importDeclaration.paths()[0];
|
|
242
|
+
this.logVerbose(`Resolved fallback value from member expression: ${chalk.yellow(fallbackValue)}`);
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
this.logError(`Could not find import for member expression: ${chalk.yellow(rawFallbackValue)}`);
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
rawFallbackValue,
|
|
249
|
+
fallbackValue,
|
|
250
|
+
resolvedImportDeclaration,
|
|
251
|
+
resolvedLocalVarDeclaration: undefined
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
async processFallbackAsTemplateLiteral(fallbackValueNode) {
|
|
255
|
+
const expressions = fallbackValueNode.expressions;
|
|
256
|
+
let rawFallbackValue = '';
|
|
257
|
+
let fallbackValue;
|
|
258
|
+
const quasis = fallbackValueNode.quasis;
|
|
259
|
+
if (expressions.length !== 1 || quasis.length !== 2) {
|
|
260
|
+
this.logError(`Unsupported template literal structure`);
|
|
261
|
+
return {
|
|
262
|
+
rawFallbackValue,
|
|
263
|
+
fallbackValue,
|
|
264
|
+
resolvedImportDeclaration: undefined,
|
|
265
|
+
resolvedLocalVarDeclaration: undefined
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
let exprValue;
|
|
269
|
+
const expression = expressions[0];
|
|
270
|
+
let resolvedImportDeclaration;
|
|
271
|
+
let resolvedLocalVarDeclaration;
|
|
272
|
+
if (expression.type === 'Identifier') {
|
|
273
|
+
const result = await this.processFallbackAsIdentifier(expression);
|
|
274
|
+
exprValue = result.fallbackValue;
|
|
275
|
+
resolvedImportDeclaration = result.resolvedImportDeclaration;
|
|
276
|
+
resolvedLocalVarDeclaration = result.resolvedLocalVarDeclaration;
|
|
277
|
+
} else if (expression.type === 'MemberExpression') {
|
|
278
|
+
const result = await this.processFallbackAsMemberExpression(expression);
|
|
279
|
+
exprValue = result.fallbackValue;
|
|
280
|
+
resolvedImportDeclaration = result.resolvedImportDeclaration;
|
|
281
|
+
}
|
|
282
|
+
if (exprValue !== undefined) {
|
|
283
|
+
rawFallbackValue = `${quasis[0].value.raw}\${${exprValue}}${quasis[1].value.raw}`;
|
|
284
|
+
fallbackValue = `${quasis[0].value.cooked}${exprValue}${quasis[1].value.cooked}`;
|
|
285
|
+
this.logVerbose(`Resolved fallback value from template literal: ${chalk.yellow(fallbackValue)}`);
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
rawFallbackValue,
|
|
289
|
+
fallbackValue,
|
|
290
|
+
resolvedImportDeclaration,
|
|
291
|
+
resolvedLocalVarDeclaration
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
tryResolveModulePath(moduleName) {
|
|
295
|
+
try {
|
|
296
|
+
const resolvedPath = require.resolve(moduleName, {
|
|
297
|
+
paths: [this.rootDir]
|
|
298
|
+
});
|
|
299
|
+
this.logVerbose(`Resolved module path: ${chalk.green(resolvedPath)} for ${chalk.cyan(moduleName)}`);
|
|
300
|
+
return resolvedPath;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async tryResolveLocalPath(currentDir, importPath) {
|
|
306
|
+
for (const ext of this.possibleExtensions) {
|
|
307
|
+
const potentialPath = path.resolve(currentDir, `${importPath}${ext}`);
|
|
308
|
+
try {
|
|
309
|
+
await fs.access(potentialPath);
|
|
310
|
+
this.logVerbose(`Resolved file path locally: ${chalk.green(potentialPath)}`);
|
|
311
|
+
return potentialPath;
|
|
312
|
+
} catch {
|
|
313
|
+
// Continue if the file is not found
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
async resolveValueFromImport(currentDir, importPath, objectName, propertyOrVariableName) {
|
|
319
|
+
let filePath = this.tryResolveModulePath(importPath);
|
|
320
|
+
if (!filePath) {
|
|
321
|
+
filePath = await this.tryResolveLocalPath(currentDir, importPath);
|
|
322
|
+
}
|
|
323
|
+
if (!filePath) {
|
|
324
|
+
this.logError(`File not found for import path: ${chalk.cyan(importPath)} in directory: ${chalk.blue(this.rootDir)}`);
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
this.logVerbose(`Reading file: ${chalk.green(filePath)}`);
|
|
328
|
+
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
329
|
+
const source = this.j(fileContent);
|
|
330
|
+
if (objectName) {
|
|
331
|
+
// Check if the object is imported from another module
|
|
332
|
+
const imports = source.find(this.j.ImportDeclaration);
|
|
333
|
+
const matchingImport = imports.filter(this.createImportFilter(objectName)).at(0);
|
|
334
|
+
if (matchingImport.size()) {
|
|
335
|
+
var _importDecl$source$va;
|
|
336
|
+
const importDecl = matchingImport.get().node;
|
|
337
|
+
const newImportPath = (_importDecl$source$va = importDecl.source.value) === null || _importDecl$source$va === void 0 ? void 0 : _importDecl$source$va.toString();
|
|
338
|
+
return this.resolveValueFromImport(path.dirname(filePath), newImportPath, objectName, propertyOrVariableName);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// If not imported, check for variable declaration
|
|
342
|
+
const varDeclaration = source.find(this.j.VariableDeclarator, {
|
|
343
|
+
id: {
|
|
344
|
+
name: propertyOrVariableName
|
|
345
|
+
}
|
|
346
|
+
}).at(0);
|
|
347
|
+
if (!varDeclaration.size()) {
|
|
348
|
+
this.logError(`Variable declaration not found for ${chalk.yellow(propertyOrVariableName)} in file: ${chalk.green(filePath)}`);
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
const init = varDeclaration.get().value.init;
|
|
352
|
+
if (init.type === 'Literal' || init.type === 'StringLiteral' || init.type === 'NumericLiteral') {
|
|
353
|
+
return init.value;
|
|
354
|
+
} else {
|
|
355
|
+
this.logError(`Unhandled init type ${init.type} for variable: ${chalk.yellow(propertyOrVariableName)} in file: ${chalk.green(filePath)}`);
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
createImportFilter(targetName) {
|
|
360
|
+
return path => {
|
|
361
|
+
var _path$node$specifiers;
|
|
362
|
+
return ((_path$node$specifiers = path.node.specifiers) === null || _path$node$specifiers === void 0 ? void 0 : _path$node$specifiers.some(specifier => {
|
|
363
|
+
var _specifier$local, _specifier$local2, _specifier$local3;
|
|
364
|
+
switch (specifier.type) {
|
|
365
|
+
case 'ImportNamespaceSpecifier':
|
|
366
|
+
return ((_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name) === targetName;
|
|
367
|
+
case 'ImportDefaultSpecifier':
|
|
368
|
+
return ((_specifier$local2 = specifier.local) === null || _specifier$local2 === void 0 ? void 0 : _specifier$local2.name) === targetName;
|
|
369
|
+
case 'ImportSpecifier':
|
|
370
|
+
return ((_specifier$local3 = specifier.local) === null || _specifier$local3 === void 0 ? void 0 : _specifier$local3.name) === targetName || specifier.imported.name === targetName;
|
|
371
|
+
default:
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
})) === true;
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|