@elliemae/ds-codemods 3.31.0-next.3 → 3.31.0-next.4
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/bin/cli/code-mods/command-logics/components-usage-report/dimsumImportStatementsRegExp.mjs +55 -0
- package/bin/cli/code-mods/command-logics/components-usage-report/index.mjs +46 -0
- package/bin/cli/code-mods/command-logics/components-usage-report/utils.mjs +320 -0
- package/bin/cli/code-mods/command-logics/execute-commands-map.mjs +4 -0
- package/bin/cli/code-mods/commands.mjs +1 -0
- package/bin/cli/code-mods/inquirer-questions-prompter.mjs +1 -0
- package/package.json +8 -5
package/bin/cli/code-mods/command-logics/components-usage-report/dimsumImportStatementsRegExp.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// eslint-disable-next-line max-len, max-len
|
|
2
|
+
// /^import\s*((?:[\S]*(?:\s*as\s*[\S]*)?(?:\s*,\s*(?:(?:[\S]*\s*as\s*[\S]*)|(?:\{(?:[\s\S](?!{))*?\})))?)|(?:\{(?:[\s\S](?!{))*?\}))\s*from\s*['"](@elliemae\/ds-\S+)['"]/gms
|
|
3
|
+
/*
|
|
4
|
+
reg-exp divided into units for readability:
|
|
5
|
+
^import\s* - matches "import" followed by any number of spaces,
|
|
6
|
+
constraints the match to the beginning of the line
|
|
7
|
+
( - start of the first capturing group
|
|
8
|
+
// this one captures:
|
|
9
|
+
- the default import (e.g. import Button from 'wherever')
|
|
10
|
+
- the named import (e.g. import Button as Btn from 'wherever')
|
|
11
|
+
- the default import followed by a comma (e.g. import Button, { Input } from 'wherever')
|
|
12
|
+
(?:
|
|
13
|
+
[\S]* - matches any non-whitespace character any number of times
|
|
14
|
+
this is meant to catch the default import (e.g. import Button from 'wherever')
|
|
15
|
+
(?:\s*as\s*[\S]*)? - optionally matches the named import (e.g. import Button as Btn from 'wherever')
|
|
16
|
+
|
|
17
|
+
(?: - optionally matches imports with comma after them
|
|
18
|
+
(e.g. import Button, { Input } from 'wherever')
|
|
19
|
+
\s*,\s* - matches a comma, with any number of spaces before and after it
|
|
20
|
+
- in ESM after a comma you have a named default import or a destructured import...
|
|
21
|
+
(?:
|
|
22
|
+
(?:[\S]*\s*as\s*[\S]*) - the catching of "default" imports as above,
|
|
23
|
+
no optional named import because after comma you can't repeat the default import
|
|
24
|
+
|
|
|
25
|
+
(?:\{ - between curly braces START
|
|
26
|
+
(?:[\s\S] - anything (including new lines)
|
|
27
|
+
(?!{) - as long as it's not followed by another curly brace
|
|
28
|
+
(avoid matching import from other packages followed by import from @elliemae/ds-* )
|
|
29
|
+
)*?
|
|
30
|
+
\}) - between curly braces END
|
|
31
|
+
)
|
|
32
|
+
)?
|
|
33
|
+
)
|
|
34
|
+
| - OR
|
|
35
|
+
// this one captures:
|
|
36
|
+
- the destructured import (e.g. import { Button } from 'wherever')
|
|
37
|
+
(?:\{ - between curly braces START
|
|
38
|
+
(?:[\s\S] - anything (including new lines)
|
|
39
|
+
(?!{) - as long as it's not followed by another curly brace
|
|
40
|
+
(avoid matching import from other packages followed by import from @elliemae/ds-* )
|
|
41
|
+
)*?
|
|
42
|
+
\}) - between curly braces END
|
|
43
|
+
|
|
44
|
+
)
|
|
45
|
+
\s*from\s* - matches "from" with any number of spaces before and after it
|
|
46
|
+
- matches a string between single or double quotes that starts with "@elliemae/ds-*"
|
|
47
|
+
['"]
|
|
48
|
+
(@elliemae\/ds-\S+)
|
|
49
|
+
['"]
|
|
50
|
+
|
|
51
|
+
https://regex101.com/r/7BsJPF/1
|
|
52
|
+
*/
|
|
53
|
+
export const dimsumImportStatementsRegExp =
|
|
54
|
+
// eslint-disable-next-line max-len
|
|
55
|
+
/^import\s*((?:[\S]*(?:\s*as\s*[\S]*)?(?:\s*,\s*(?:(?:[\S]*\s*as\s*[\S]*)|(?:\{(?:[\s\S](?!{))*?\})))?)|(?:\{(?:[\s\S](?!{))*?\}))\s*from\s*['"](@elliemae\/ds-\S+)['"]/gms;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { createCSVReport } from './utils.mjs';
|
|
3
|
+
|
|
4
|
+
const writeReport = (options, csvRows) => {
|
|
5
|
+
const { outputPath, append } = options;
|
|
6
|
+
if (!append) {
|
|
7
|
+
fs.writeFileSync(outputPath, csvRows.join('\n'));
|
|
8
|
+
} else {
|
|
9
|
+
// when we append we do not want to repeat the header, instead we want to add a new line
|
|
10
|
+
// we check if the file exists and if it does we check if the first line is the header
|
|
11
|
+
const fileExists = fs.existsSync(outputPath);
|
|
12
|
+
let shouldAddHeader = true;
|
|
13
|
+
if (fileExists) {
|
|
14
|
+
const fileContent = fs.readFileSync(outputPath, 'utf8');
|
|
15
|
+
const firstLine = fileContent.split('\n')[0];
|
|
16
|
+
if (firstLine === csvRows[0]) {
|
|
17
|
+
shouldAddHeader = false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (!shouldAddHeader) {
|
|
21
|
+
// since we are appending, the first line is left empty, this way the csvRows.join('\n') will add a new line
|
|
22
|
+
csvRows[0] = '';
|
|
23
|
+
}
|
|
24
|
+
fs.appendFileSync(outputPath, csvRows.join('\n'));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* generates a report of deprecated components usage
|
|
30
|
+
* @param {object} options - options *
|
|
31
|
+
* @param {string} options.outputPath - path to the .csv file to write the report to
|
|
32
|
+
* @param {string} options.startingDirPath - path to the project root directory (where node_modules folder lives)
|
|
33
|
+
* @param {string} options.gitIgnorePath - path to the .gitignore file
|
|
34
|
+
* @param {string} options.org - optional org, if present an extra column will be added to the report
|
|
35
|
+
* @param {string} options.repo - optional repo, if present an extra column will be added to the report
|
|
36
|
+
* @param {boolean} options.debug - debug flag
|
|
37
|
+
* @param {boolean} options.append - whether to append to the file or override it
|
|
38
|
+
*
|
|
39
|
+
* @returns {void}
|
|
40
|
+
*/
|
|
41
|
+
export const componentsUsageReport = (options) => {
|
|
42
|
+
const csvRows = createCSVReport(options);
|
|
43
|
+
writeReport(options, csvRows);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default componentsUsageReport;
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/* eslint-disable max-params, max-lines, max-statements, max-len */
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { filePathsWithGitIgnore } from '../../../utils/filepathsMatchers.mjs';
|
|
4
|
+
import { dimsumImportStatementsRegExp } from './dimsumImportStatementsRegExp.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} ImportAllAsResults
|
|
8
|
+
* @property {string} fullMatch
|
|
9
|
+
* @property {string} renamedAs
|
|
10
|
+
*
|
|
11
|
+
* @typedef {Object} DefaultImportResults
|
|
12
|
+
* @property {string} fullMatch
|
|
13
|
+
* @property {string} renamedAs
|
|
14
|
+
*
|
|
15
|
+
* @typedef {Object} PartialNamedImport
|
|
16
|
+
* @property {string} namedImportWithRename[number].partialFullMatch
|
|
17
|
+
* @property {string} namedImportWithRename[number].component
|
|
18
|
+
* @property {string|undefined} namedImportWithRename[number].renamedTo
|
|
19
|
+
*
|
|
20
|
+
* @typedef {PartialNamedImport[]} NamedImportResults
|
|
21
|
+
*
|
|
22
|
+
* @typedef { object } ImportsFlags
|
|
23
|
+
* @property {boolean} hasRelationWithDimsum
|
|
24
|
+
*
|
|
25
|
+
*
|
|
26
|
+
* @typedef {Object} fileImportsInfos
|
|
27
|
+
* @property {ImportAllAsResults[]} globalRenameImports
|
|
28
|
+
* @property {DefaultImportResults[]} importedDefaults
|
|
29
|
+
* @property {namedImportWithoutRename[]} importedNamedComponentsWithoutRename
|
|
30
|
+
* @property {namedImportWithRename[]} importedNamedComponentsWithRename
|
|
31
|
+
*
|
|
32
|
+
* @typedef {ImportsFlags & fileImportsInfos & Object} FileReport
|
|
33
|
+
* @property {string} filePath
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
// specific regexp to distinguish 'import * as X from "Y"'
|
|
37
|
+
/**
|
|
38
|
+
* given an ESM import statement as a string, it returns the renamed all as alias if present
|
|
39
|
+
* @param {string} importStatement - the import statement to parse
|
|
40
|
+
* @returns {ImportAllAsResults | undefined}
|
|
41
|
+
* if renamed all as alias is present returns an object with the full match and the renamed all as alias
|
|
42
|
+
*
|
|
43
|
+
* if no renamed all as alias is present returns undefined
|
|
44
|
+
* @example
|
|
45
|
+
* renameAllAs('import * as X from "Y"') // { fullMatch: 'import * as X from "Y"', renamedAs: 'X' }
|
|
46
|
+
* renameAllAs('import X from "Y"') // undefined
|
|
47
|
+
*/
|
|
48
|
+
const renameAllAs = (importStatement) => {
|
|
49
|
+
const renameAllAsRegex = /\*\s+as\s+(\w+)/gms;
|
|
50
|
+
// using matchAll because match doesn't preserve the capturing groups...
|
|
51
|
+
const matches = importStatement.matchAll(renameAllAsRegex);
|
|
52
|
+
const match = [...matches][0];
|
|
53
|
+
if (!match) return undefined;
|
|
54
|
+
return {
|
|
55
|
+
fullMatch: importStatement,
|
|
56
|
+
renamedAs: match[1],
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* given an ESM import statement as a string, it returns the default import alias if present
|
|
62
|
+
* @param {string} importStatement - the import statement to parse
|
|
63
|
+
* @returns {DefaultImportResults | undefined}
|
|
64
|
+
* if default import alias is present returns an object with the full match and the default import alias
|
|
65
|
+
*
|
|
66
|
+
* if no default import alias is present returns undefined
|
|
67
|
+
* @example
|
|
68
|
+
* defaultImport('import X from "Y"') // { fullMatch: 'import X from "Y"', renamedAs: 'X' }
|
|
69
|
+
* defaultImport('import X, { A, B } from "Y"') // { fullMatch: 'import X, { A, B } from "Y"', renamedAs: 'X' }
|
|
70
|
+
* defaultImport('import { A, B } from "Y"') // undefined
|
|
71
|
+
*/
|
|
72
|
+
const defaultImport = (importStatement) => {
|
|
73
|
+
const defaultImportRegex = /^import\s*(\w+)(?:,\s(?:\{(?:[\s\S](?!{))*?\}))*/gms;
|
|
74
|
+
// using matchAll because match doesn't preserve the capturing groups...
|
|
75
|
+
const matches = importStatement.matchAll(defaultImportRegex);
|
|
76
|
+
const match = [...matches][0];
|
|
77
|
+
if (!match) return undefined;
|
|
78
|
+
/** @type {DefaultImportResults} */
|
|
79
|
+
return {
|
|
80
|
+
fullMatch: importStatement,
|
|
81
|
+
renamedAs: match[1],
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* given the curly braces part of an ESM import statement, it returns the named imports with and without rename
|
|
87
|
+
* @param {string} curlyBracesImportString - the curly braces part of an ESM import statement
|
|
88
|
+
* @returns {NamedImportResults}
|
|
89
|
+
* an array with the named imports info
|
|
90
|
+
*
|
|
91
|
+
* if not named imports are present in the curly braces block the array will be empty (length 0)
|
|
92
|
+
* @example
|
|
93
|
+
* namedImports('{ A, B, C }')
|
|
94
|
+
* // [
|
|
95
|
+
* // { partialFullMatch: 'A', component: 'A', renamedTo: undefined},
|
|
96
|
+
* // { partialFullMatch: 'B', component: 'B', renamedTo: undefined},
|
|
97
|
+
* // { partialFullMatch: 'C', component: 'C', renamedTo: undefined}
|
|
98
|
+
* // ]
|
|
99
|
+
* namedImports('{ A as X, B as Y, C as Z }')
|
|
100
|
+
* // [
|
|
101
|
+
* // { partialFullMatch: 'A as X', component: 'A', renamedTo: 'X' },
|
|
102
|
+
* // { partialFullMatch: 'B as Y', component: 'B', renamedTo: 'Y' },
|
|
103
|
+
* // { partialFullMatch: 'C as Z', component: 'C', renamedTo: 'Z' }
|
|
104
|
+
* // ]
|
|
105
|
+
* namedImports('{ A, B as Y, C }')
|
|
106
|
+
* // [
|
|
107
|
+
* // { partialFullMatch: 'B as Y', component: 'B', renamedTo: 'Y' }
|
|
108
|
+
* // { partialFullMatch: 'A', component: 'A', renamedTo: undefined},
|
|
109
|
+
* // { partialFullMatch: 'C', component: 'C', renamedTo: undefined}
|
|
110
|
+
* // ]
|
|
111
|
+
*/
|
|
112
|
+
const namedImports = (curlyBracesImportString) => {
|
|
113
|
+
// the following two regexps must be used in a previously "between braces" match to work as expected
|
|
114
|
+
const namedWithRenameRegex = /(\w+)\sas\s+(\w+)/gms;
|
|
115
|
+
const namedImportsWithoutRenameRegex =
|
|
116
|
+
/(?<=^[{\s]+)\w+\b(?!\b\s+as\s+\w+)|(?<=,\s+)\b\w+\b(?=\s*,)|(?<!(?:as)|(?:type)\s+)\b\w+(?=\s+})/gms;
|
|
117
|
+
// ----------
|
|
118
|
+
// using matchAll because match doesn't preserve the capturing groups...
|
|
119
|
+
const namedImportWithRenameMatches = [...curlyBracesImportString.matchAll(namedWithRenameRegex)];
|
|
120
|
+
const namedImportWithRename = namedImportWithRenameMatches.map((match) => ({
|
|
121
|
+
partialFullMatch: match[0],
|
|
122
|
+
component: match[1],
|
|
123
|
+
renamedTo: match[2],
|
|
124
|
+
}));
|
|
125
|
+
const namedImportWithoutRenameMatches = [...curlyBracesImportString.matchAll(namedImportsWithoutRenameRegex)];
|
|
126
|
+
const namedImportWithoutRename = namedImportWithoutRenameMatches.map((match) => ({
|
|
127
|
+
partialFullMatch: match[0],
|
|
128
|
+
component: match[0],
|
|
129
|
+
renamedTo: undefined,
|
|
130
|
+
}));
|
|
131
|
+
return [...namedImportWithRename, ...namedImportWithoutRename];
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// const fileReset = (filePath) => {
|
|
135
|
+
// if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
136
|
+
// };
|
|
137
|
+
|
|
138
|
+
// const fileUpsert = (filePath, content) => {
|
|
139
|
+
// const fileExists = fs.existsSync(filePath);
|
|
140
|
+
// if (!fileExists) fs.writeFileSync(filePath, content);
|
|
141
|
+
// else fs.appendFileSync(filePath, content);
|
|
142
|
+
// };
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* given a file path, it checks if the file contains any dimsum components
|
|
146
|
+
* @param {string} filePath - path to the file to check
|
|
147
|
+
* @returns {FileReport} - a report of the file
|
|
148
|
+
*/
|
|
149
|
+
export const getFileReport = (filePath) => {
|
|
150
|
+
const fileAsString = fs.readFileSync(filePath, 'utf8');
|
|
151
|
+
const matches = fileAsString.matchAll(dimsumImportStatementsRegExp);
|
|
152
|
+
const importStatements = [...matches]; // convert iterator to array - matchAll returns an iterator...
|
|
153
|
+
|
|
154
|
+
/** @type {FileReport} */
|
|
155
|
+
const fileReport = {
|
|
156
|
+
filePath,
|
|
157
|
+
hasRelationWithDimsum: importStatements.length > 0,
|
|
158
|
+
globalRenameImports: [],
|
|
159
|
+
importedDefaults: [],
|
|
160
|
+
importedNamedComponentsWithoutRename: [],
|
|
161
|
+
importedNamedComponentsWithRename: [],
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
importStatements.forEach((match) => {
|
|
165
|
+
const fullMatch = match[0];
|
|
166
|
+
const importedComponent = match[1];
|
|
167
|
+
const packageName = match[2];
|
|
168
|
+
const importAllAsInfo = renameAllAs(fullMatch);
|
|
169
|
+
const defaultImportInfo = defaultImport(fullMatch);
|
|
170
|
+
const partialNamedInfoData = namedImports(importedComponent);
|
|
171
|
+
if (importAllAsInfo) fileReport.globalRenameImports.push({ ...importAllAsInfo, packageName, fullMatch });
|
|
172
|
+
if (defaultImportInfo) fileReport.importedDefaults.push({ ...defaultImportInfo, packageName, fullMatch });
|
|
173
|
+
if (partialNamedInfoData.length !== 0)
|
|
174
|
+
partialNamedInfoData.forEach((partialNamedInfo) => {
|
|
175
|
+
const namedImportItem = {
|
|
176
|
+
component: partialNamedInfo.component,
|
|
177
|
+
packageName,
|
|
178
|
+
fullMatch,
|
|
179
|
+
};
|
|
180
|
+
if (partialNamedInfo.renamedTo)
|
|
181
|
+
fileReport.importedNamedComponentsWithRename.push({
|
|
182
|
+
...namedImportItem,
|
|
183
|
+
renamedTo: partialNamedInfo.renamedTo,
|
|
184
|
+
});
|
|
185
|
+
else fileReport.importedNamedComponentsWithoutRename.push(namedImportItem);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return fileReport;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* given a datum and a file path and options, generates a csv row
|
|
193
|
+
*/
|
|
194
|
+
const generateCSVRow = (datum, filePath, options) => {
|
|
195
|
+
// "Org(?),Imported Component,Repository(?),Package Name,Renamed Alias,File Path
|
|
196
|
+
const { importedComponent, packageName, renamedAs } = datum;
|
|
197
|
+
return `${options.org ? `${options.org},` : ''}${importedComponent},${
|
|
198
|
+
options.repo ? `${options.repo},` : ''
|
|
199
|
+
}${packageName},${renamedAs},${filePath}`;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* given a file report, generates related csv rows (one or more)
|
|
204
|
+
* @param {FileReport} fileReport - the file report to generate the csv rows from
|
|
205
|
+
* @returns {string[]} - the csv rows flattened per relevant columns distinguishers
|
|
206
|
+
*
|
|
207
|
+
*/
|
|
208
|
+
const generateCSVRows = (fileReport, options) => {
|
|
209
|
+
const {
|
|
210
|
+
filePath,
|
|
211
|
+
hasRelationWithDimsum,
|
|
212
|
+
globalRenameImports,
|
|
213
|
+
importedDefaults,
|
|
214
|
+
importedNamedComponentsWithoutRename,
|
|
215
|
+
importedNamedComponentsWithRename,
|
|
216
|
+
} = fileReport;
|
|
217
|
+
const csvRows = [];
|
|
218
|
+
if (hasRelationWithDimsum) {
|
|
219
|
+
// opinionated way to describe a global rename import in the csv
|
|
220
|
+
// the opinion is: Imported Component: *, Renamed Alias: <the renamed alias>
|
|
221
|
+
if (globalRenameImports.length > 0) {
|
|
222
|
+
globalRenameImports.forEach((globalRenameImport) => {
|
|
223
|
+
csvRows.push(
|
|
224
|
+
generateCSVRow(
|
|
225
|
+
{
|
|
226
|
+
importedComponent: '*',
|
|
227
|
+
packageName: globalRenameImport.packageName,
|
|
228
|
+
renamedAs: globalRenameImport.renamedAs,
|
|
229
|
+
},
|
|
230
|
+
filePath,
|
|
231
|
+
options,
|
|
232
|
+
),
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
// opinionated way to describe a default import in the csv
|
|
237
|
+
// the opinion is: Imported Component: 'default', Renamed Alias: <the renamed alias>
|
|
238
|
+
if (importedDefaults.length > 0) {
|
|
239
|
+
importedDefaults.forEach((importedDefault) => {
|
|
240
|
+
csvRows.push(
|
|
241
|
+
generateCSVRow(
|
|
242
|
+
{
|
|
243
|
+
importedComponent: 'default',
|
|
244
|
+
packageName: importedDefault.packageName,
|
|
245
|
+
renamedAs: importedDefault.renamedAs,
|
|
246
|
+
},
|
|
247
|
+
filePath,
|
|
248
|
+
options,
|
|
249
|
+
),
|
|
250
|
+
);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
// opinionated way to describe a named import that wasn't renamed in the csv
|
|
254
|
+
// the opinion is: Imported Component: <the named import>, Renamed Alias: ''
|
|
255
|
+
if (importedNamedComponentsWithoutRename.length > 0) {
|
|
256
|
+
importedNamedComponentsWithoutRename.forEach((importedNamedComponent) => {
|
|
257
|
+
csvRows.push(
|
|
258
|
+
generateCSVRow(
|
|
259
|
+
{
|
|
260
|
+
importedComponent: importedNamedComponent.component,
|
|
261
|
+
packageName: importedNamedComponent.packageName,
|
|
262
|
+
renamedAs: '',
|
|
263
|
+
},
|
|
264
|
+
filePath,
|
|
265
|
+
options,
|
|
266
|
+
),
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (importedNamedComponentsWithRename.length > 0) {
|
|
272
|
+
importedNamedComponentsWithRename.forEach((importedNamedComponent) => {
|
|
273
|
+
csvRows.push(
|
|
274
|
+
generateCSVRow(
|
|
275
|
+
{
|
|
276
|
+
importedComponent: importedNamedComponent.component,
|
|
277
|
+
packageName: importedNamedComponent.packageName,
|
|
278
|
+
renamedAs: importedNamedComponent.renamedTo,
|
|
279
|
+
},
|
|
280
|
+
filePath,
|
|
281
|
+
options,
|
|
282
|
+
),
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return csvRows;
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* generates a report of components usage
|
|
291
|
+
* @param {object} options - options *
|
|
292
|
+
* @param {string} options.outputPath - path to the .csv file to write the report to
|
|
293
|
+
* @param {string} options.startingDirPath - path to the project root directory (where node_modules folder lives)
|
|
294
|
+
* @param {string} options.gitIgnorePath - path to the .gitignore file
|
|
295
|
+
* @param {string} options.org - optional org, if present an extra column will be added to the report
|
|
296
|
+
* @param {string} options.repo - optional repo, if present an extra column will be added to the report
|
|
297
|
+
* @param {boolean} options.debug - debug flag
|
|
298
|
+
* @param {boolean} options.append - whether to append to the file or override it
|
|
299
|
+
*
|
|
300
|
+
* @returns {string[]} - the csv rows, always starting with the header
|
|
301
|
+
*/
|
|
302
|
+
export const createCSVReport = (options) => {
|
|
303
|
+
const filesToParse = filePathsWithGitIgnore(options);
|
|
304
|
+
|
|
305
|
+
let csvRows = [
|
|
306
|
+
generateCSVRow(
|
|
307
|
+
{ importedComponent: 'Imported Component', packageName: 'Package Name', renamedAs: 'Renamed Alias' },
|
|
308
|
+
'File Path',
|
|
309
|
+
{ ...options, org: options.org ? 'Org' : undefined, repo: options.repo ? 'Repository' : undefined },
|
|
310
|
+
),
|
|
311
|
+
];
|
|
312
|
+
|
|
313
|
+
filesToParse.forEach((filePath) => {
|
|
314
|
+
const fileReport = getFileReport(filePath);
|
|
315
|
+
const fileCSVRows = generateCSVRows(fileReport, options);
|
|
316
|
+
csvRows.push(...fileCSVRows);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
return csvRows;
|
|
320
|
+
};
|
|
@@ -4,6 +4,7 @@ import { checkMissingPackages } from './check-missing-packages/index.mjs';
|
|
|
4
4
|
import { checkDeprecatedPackages } from './check-deprecated-packages/index.mjs';
|
|
5
5
|
import { helpMigrateToV3 } from './help-migrate-to-v3/index.mjs';
|
|
6
6
|
import { deprecatedComponentsUsageReport } from './deprecated-components-usage-report/index.mjs';
|
|
7
|
+
import { componentsUsageReport } from './components-usage-report/index.mjs';
|
|
7
8
|
import { COMMANDS } from '../commands.mjs';
|
|
8
9
|
|
|
9
10
|
export async function executeCommandsMap(args, options) {
|
|
@@ -29,6 +30,9 @@ export async function executeCommandsMap(args, options) {
|
|
|
29
30
|
case COMMANDS.DEPRECATED_PACKAGES_USAGE_REPORT:
|
|
30
31
|
deprecatedComponentsUsageReport(options);
|
|
31
32
|
break;
|
|
33
|
+
case COMMANDS.COMPONENT_USAGE_REPORT:
|
|
34
|
+
componentsUsageReport(options);
|
|
35
|
+
break;
|
|
32
36
|
default:
|
|
33
37
|
break;
|
|
34
38
|
}
|
|
@@ -6,6 +6,7 @@ export const COMMANDS = {
|
|
|
6
6
|
CHECK_MISSING_PACKAGES: 'check-missing-packages',
|
|
7
7
|
HELP_MIGRATE_TO_V3: 'help-migrate-to-v3',
|
|
8
8
|
DEPRECATED_PACKAGES_USAGE_REPORT: 'deprecated-components-usage-report',
|
|
9
|
+
COMPONENT_USAGE_REPORT: 'components-usage-report',
|
|
9
10
|
EXIT: 'exit',
|
|
10
11
|
};
|
|
11
12
|
|
|
@@ -27,6 +27,7 @@ async function promptForMissingScriptSpecificOptions({ originalOptions, promptOp
|
|
|
27
27
|
case COMMANDS.HELP_MIGRATE_TO_V3:
|
|
28
28
|
scriptQuestions.push(...getHelpMigrateToV3Questions(originalOptions));
|
|
29
29
|
break;
|
|
30
|
+
case COMMANDS.COMPONENT_USAGE_REPORT:
|
|
30
31
|
case COMMANDS.DEPRECATED_PACKAGES_USAGE_REPORT:
|
|
31
32
|
scriptQuestions.push(...getDeprecatedUsageReportQuestions(originalOptions));
|
|
32
33
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-codemods",
|
|
3
|
-
"version": "3.31.0-next.
|
|
3
|
+
"version": "3.31.0-next.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - Code Mods",
|
|
6
6
|
"files": [
|
|
@@ -47,12 +47,15 @@
|
|
|
47
47
|
"typeSafety": false
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
|
-
"try-codemods": "npx ./",
|
|
51
50
|
"dev:install": "pnpm --filter {.}... i --no-lockfile",
|
|
52
51
|
"eslint:fix": "eslint --ext='.js,.jsx,.test.js,.ts,.tsx' --fix --config='../../.eslintrc.js' bin/",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
52
|
+
"test-codemods": "npx ./",
|
|
53
|
+
"test-check-deprecated-packages": "npx ./ check-deprecated-packages --cwd=\"test-ables/check-deprecated-packages/with-deprecated\"",
|
|
54
|
+
"test-check-deprecated-packages-no-dimsum": "npx ./ check-deprecated-packages --cwd=\"test-ables/check-deprecated-packages/without-dimsum-packages\"",
|
|
55
|
+
"test-components-usage-report": "npx ./ components-usage-report --outputPath=\"./test.csv\" --startingDirPath=\"../../../environments\" --gitIgnorePath=\"../../../.gitignore\"",
|
|
56
|
+
"test-components-usage-report-complete": "npx ./ components-usage-report --outputPath=\"./test.csv\" --startingDirPath=\"../../../environments\" --gitIgnorePath=\"../../../.gitignore\" --repo=\"Dimsum\" --org=\"ICE\"",
|
|
57
|
+
"test-components-usage-report-complete-append": "npx ./ components-usage-report --outputPath=\"./test.csv\" --startingDirPath=\"../../../environments\" --gitIgnorePath=\"../../../.gitignore\" --repo=\"Dimsum2\" --org=\"ICE2\"",
|
|
58
|
+
"test-help-migrate-to-v3": "npx ./ help-migrate-to-v3 --globPattern=\"test-ables/help-migrate-to-v3/**/*.js,./**/*.jsx,./**/*.ts,./**/*.tsx\" --globPatternIgnore=\"**/node_modules/**/*\"",
|
|
56
59
|
"create-package": "hygen package new",
|
|
57
60
|
"create-part": "hygen part new",
|
|
58
61
|
"checkDeps": "exit 0 | echo"
|