Skip to content

Commit 89ddeba

Browse files
author
Robert Jackson
authored
Merge pull request #16 from ember-codemods/cleanup
2 parents ea6a3b2 + df5dc4a commit 89ddeba

24 files changed

+805
-399
lines changed

.eslintignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# do not ignore dotfiles
2+
!.*
3+
.git/
4+
5+
/node_modules

.eslintrc.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = {
2+
root: true,
3+
parserOptions: {
4+
ecmaVersion: 2019,
5+
sourceType: 'script',
6+
},
7+
extends: ['eslint:recommended', 'plugin:node/recommended', 'plugin:prettier/recommended'],
8+
plugins: ['prettier', 'node'],
9+
env: {
10+
node: true,
11+
},
12+
rules: {},
13+
overrides: [
14+
{
15+
files: ['test/**/*.js'],
16+
env: {
17+
mocha: true,
18+
},
19+
},
20+
],
21+
};

.prettierrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "es5",
4+
"printWidth": 100
5+
}

lib/migrator.js

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
const fs = require('fs');
44
const path = require('path');
5-
const glob = require("glob");
6-
const { getLayoutNameTemplates, getPartialTemplates, getImportedTemplates } = require('./utils/templates')
7-
const { moveFile, removeDirs } = require('./utils/file')
5+
const glob = require('glob');
6+
const {
7+
getLayoutNameTemplates,
8+
getPartialTemplates,
9+
getImportedTemplates,
10+
} = require('./utils/templates');
11+
const { moveFile, removeDirs } = require('./utils/file');
812
const { transform: dropLayoutBinding } = require('./utils/rewrite-imports');
9-
const { template } = require('jscodeshift');
1013

1114
/**
1215
* @typedef {object} Options
@@ -16,19 +19,16 @@ const { template } = require('jscodeshift');
1619

1720
module.exports = class Migrator {
1821
/**
19-
* @param {Options} options
22+
* @param {Options} options
2023
*/
2124
constructor({ projectRoot, structure }) {
25+
/** @type {string} */
2226
this.projectRoot = projectRoot;
27+
28+
/** @type {'flat' | 'nested'} */
2329
this.structure = structure;
2430
}
2531

26-
/** @type {string} */
27-
projectRoot;
28-
29-
/** @type {'flat' | 'nested'} */
30-
structure;
31-
3232
get appRoot() {
3333
return path.join(this.projectRoot, 'app');
3434
}
@@ -62,30 +62,36 @@ module.exports = class Migrator {
6262
}
6363

6464
findComponentTemplates() {
65-
return glob.sync(`{${this.appComponentTemplatesDir},${this.addonComponentTemplatesDir}}/**/*.hbs`);
65+
return glob.sync(
66+
`{${this.appComponentTemplatesDir},${this.addonComponentTemplatesDir}}/**/*.hbs`
67+
);
6668
}
6769

6870
findComponentClasses() {
6971
return glob.sync(`{${this.appBackingClassesDir},${this.addonBackingClassesDir}}/**/*.{js,ts}`);
7072
}
7173

7274
findAllTemplates() {
73-
return glob.sync(`{${this.appBackingClassesDir},${this.appTemplatesDir},${this.addonBackingClassesDir},${this.addonTemplatesDir}}/**/*.hbs`);
75+
return glob.sync(
76+
`{${this.appBackingClassesDir},${this.appTemplatesDir},${this.addonBackingClassesDir},${this.addonTemplatesDir}}/**/*.hbs`
77+
);
7478
}
7579

7680
/**
7781
* @param {string[]} templateFilePaths
7882
* @param {string[]} componentsWithLayoutName
7983
*/
8084
skipTemplatesUsedAsLayoutName(templateFilePaths, componentsWithLayoutName) {
81-
console.info(`\nChecking if any component templates are used as templates of other components using \`layoutName\``);
85+
console.info(
86+
`\nChecking if any component templates are used as templates of other components using \`layoutName\``
87+
);
8288

8389
if (componentsWithLayoutName.length) {
84-
componentsWithLayoutName.sort().forEach(component => {
90+
componentsWithLayoutName.sort().forEach((component) => {
8591
console.info(`❌ Did not move '${component}' due to usage as "layoutName" in a component`);
8692
});
8793

88-
templateFilePaths = templateFilePaths.filter(templateFilePath => {
94+
templateFilePaths = templateFilePaths.filter((templateFilePath) => {
8995
// Extract '/(app|addon)/templates/components/nested1/nested-component.hbs'
9096
const filePathFromApp = templateFilePath.slice(this.projectRoot.length);
9197

@@ -105,19 +111,19 @@ module.exports = class Migrator {
105111
}
106112

107113
/**
108-
* @param {string[]} templateFilePaths
114+
* @param {string[]} templateFilePaths
109115
*/
110116
skipTemplatesUsedAsPartial(templateFilePaths) {
111117
console.info(`\nChecking if any component templates are used as partials`);
112118

113119
const componentsWithPartial = getPartialTemplates(this.findAllTemplates());
114120

115121
if (componentsWithPartial.length) {
116-
componentsWithPartial.sort().forEach(component => {
122+
componentsWithPartial.sort().forEach((component) => {
117123
console.info(`❌ Did not move '${component}' due to usage as a "partial"`);
118124
});
119125

120-
templateFilePaths = templateFilePaths.filter(templateFilePath => {
126+
templateFilePaths = templateFilePaths.filter((templateFilePath) => {
121127
// Extract '/(app|addon)/templates/components/nested1/nested-component.hbs'
122128
let filePathFromApp = templateFilePath.slice(this.projectRoot.length);
123129

@@ -130,7 +136,7 @@ module.exports = class Migrator {
130136
131137
If `filePathFromApp` matches the latter pattern, we remove the hyphen.
132138
*/
133-
if (/\/\-[\w\-]+\.hbs/.test(filePathFromApp)) {
139+
if (/\/-[\w-]+\.hbs/.test(filePathFromApp)) {
134140
filePathFromApp = filePathFromApp.replace('/-', '/');
135141
}
136142

@@ -153,10 +159,8 @@ module.exports = class Migrator {
153159
* @param {string[]} templateFilePaths
154160
* @returns {string[]}
155161
*/
156-
skipTemplatesUsedInMultipleBackingClasses(templateFilePaths) {
157-
console.info(
158-
'\nChecking if any component templates are used in multiple backing classes'
159-
);
162+
skipTemplatesUsedInMultipleBackingClasses(templateFilePaths) {
163+
console.info('\nChecking if any component templates are used in multiple backing classes');
160164

161165
const componentFilePaths = this.findComponentClasses();
162166
const componentsImportingTemplates = getImportedTemplates(
@@ -171,12 +175,9 @@ module.exports = class Migrator {
171175

172176
// Map the imported template name back to the template file paths as we
173177
// have them on
174-
const importedTemplate = importedTemplates[0]
175-
.replace(/.*\/templates/gi, "templates");
178+
const importedTemplate = importedTemplates[0].replace(/.*\/templates/gi, 'templates');
176179

177-
const template = templateFilePaths.find(
178-
path => path.includes(importedTemplate)
179-
)
180+
const template = templateFilePaths.find((path) => path.includes(importedTemplate));
180181

181182
// If we've previously put this in the "allowed" bucket, we now know it
182183
// *shouldn't* be allowed, because it's used in another
@@ -197,8 +198,9 @@ module.exports = class Migrator {
197198
}
198199

199200
for (let [templatePath, importingModules] of reusedTemplates.entries()) {
200-
const importingModuleLocalPaths =
201-
importingModules.map(path => path.replace(/.*\/(app|addon)/, ""));
201+
const importingModuleLocalPaths = importingModules.map((path) =>
202+
path.replace(/.*\/(app|addon)/, '')
203+
);
202204

203205
const message =
204206
`❌ Did not move '${templatePath}' because it was imported by ` +
@@ -208,24 +210,27 @@ module.exports = class Migrator {
208210
console.info(message);
209211
}
210212

211-
const nonImported = templateFilePaths
212-
.filter(path => !allowed.has(path) && !reusedTemplates.has(path));
213+
const nonImported = templateFilePaths.filter(
214+
(path) => !allowed.has(path) && !reusedTemplates.has(path)
215+
);
213216

214217
return Array.from(allowed.keys()).concat(nonImported);
215218
}
216219

217220
/**
218-
* @param {string[]} templateFilePaths
221+
* @param {string[]} templateFilePaths
219222
*/
220223
changeComponentStructureToFlat(templateFilePaths) {
221-
templateFilePaths.forEach(templateFilePath => {
224+
templateFilePaths.forEach((templateFilePath) => {
222225
// Extract '/(app|addon)/templates/components/nested1/nested-component.hbs'
223226
const filePathFromApp = templateFilePath.slice(this.projectRoot.length);
224227

225228
const type = typeFromFilePath(filePathFromApp);
226229

227230
// Extract '/nested1/nested-component.hbs'
228-
const filePathFromAppTemplatesComponents = filePathFromApp.slice(`${type}/templates/components/`.length);
231+
const filePathFromAppTemplatesComponents = filePathFromApp.slice(
232+
`${type}/templates/components/`.length
233+
);
229234

230235
// '[APP_PATH]/(app|addon)/components/nested1/nested-component.hbs'
231236
const root = type === 'app' ? this.appRoot : this.addonRoot;
@@ -235,19 +240,21 @@ module.exports = class Migrator {
235240
}
236241

237242
/**
238-
* @param {string[]} templateFilePaths
243+
* @param {string[]} templateFilePaths
239244
*/
240245
changeComponentStructureToNested(templateFilePaths) {
241246
const classFilePaths = this.findComponentClasses();
242247

243-
templateFilePaths.forEach(templateFilePath => {
248+
templateFilePaths.forEach((templateFilePath) => {
244249
// Extract '/(app|addon)/templates/components/nested1/nested-component.hbs'
245250
const filePathFromProject = templateFilePath.slice(this.projectRoot.length);
246251

247252
const type = typeFromFilePath(filePathFromProject);
248253

249254
// Extract '/nested1/nested-component.hbs'
250-
const filePathFromAppTemplatesComponents = filePathFromProject.slice(`${type}/templates/components/`.length);
255+
const filePathFromAppTemplatesComponents = filePathFromProject.slice(
256+
`${type}/templates/components/`.length
257+
);
251258
const fileExtension = path.extname(filePathFromAppTemplatesComponents);
252259

253260
// Extract '/nested1/nested-component'
@@ -261,42 +268,39 @@ module.exports = class Migrator {
261268
// Build '[APP_PATH]/(app|addon)/components/nested1/nested-component/index.js'
262269
const classFilePath = {
263270
js: path.join(root, 'components', `${targetPath}.js`),
264-
ts: path.join(root, 'components', `${targetPath}.ts`)
271+
ts: path.join(root, 'components', `${targetPath}.ts`),
265272
};
266273

267274
if (classFilePaths.includes(classFilePath.js)) {
268275
const newClassFilePath = path.join(root, 'components', targetPath, 'index.js');
269276
moveFile(classFilePath.js, newClassFilePath);
270-
271277
} else if (classFilePaths.includes(classFilePath.ts)) {
272278
const newClassFilePath = path.join(root, 'components', targetPath, 'index.ts');
273279
moveFile(classFilePath.ts, newClassFilePath);
274-
275280
}
276281
});
277282
}
278283

279284
/**
280-
* @param {string[]} templateFilePaths
285+
* @param {string[]} templateFilePaths
281286
*/
282287
removeLayoutBinding(templateFilePaths) {
283-
templateFilePaths.forEach(templateFilePath => {
288+
templateFilePaths.forEach((templateFilePath) => {
284289
// Extract '/(app|addon)/templates/components/nested1/nested-component.hbs'
285-
const filePathFromProject = templateFilePath
286-
.slice(this.projectRoot.length);
287-
290+
const filePathFromProject = templateFilePath.slice(this.projectRoot.length);
291+
288292
const backingJsClassProjectPath = filePathFromProject
289293
.replace('templates/components', 'components')
290294
.replace('.hbs', '.js');
291-
295+
292296
const backingTsClassProjectPath = filePathFromProject
293297
.replace('templates/components', 'components')
294298
.replace('.hbs', '.ts');
295-
296-
const backingClassPaths =
297-
[backingJsClassProjectPath, backingTsClassProjectPath].map(
298-
backingClassPath => path.join(this.projectRoot, backingClassPath)
299-
);
299+
300+
const backingClassPaths = [
301+
backingJsClassProjectPath,
302+
backingTsClassProjectPath,
303+
].map((backingClassPath) => path.join(this.projectRoot, backingClassPath));
300304

301305
backingClassPaths.forEach((path) => {
302306
if (fs.existsSync(path)) {
@@ -306,7 +310,7 @@ module.exports = class Migrator {
306310
fs.writeFileSync(path, updatedContent);
307311
}
308312
}
309-
})
313+
});
310314
});
311315
}
312316

@@ -323,7 +327,7 @@ module.exports = class Migrator {
323327
const removeOnlyEmptyDirectories = Boolean(
324328
templatesWithLayoutName.length + componentsImportingTemplates.length
325329
);
326-
330+
327331
await removeDirs(this.appComponentTemplatesDir, removeOnlyEmptyDirectories);
328332
await removeDirs(this.addonComponentTemplatesDir, removeOnlyEmptyDirectories);
329333
}
@@ -333,28 +337,29 @@ module.exports = class Migrator {
333337
const componentsWithLayoutName = getLayoutNameTemplates(classFilePaths);
334338

335339
let templateFilePaths = this.findComponentTemplates();
336-
templateFilePaths = this.skipTemplatesUsedAsLayoutName(templateFilePaths, componentsWithLayoutName);
340+
templateFilePaths = this.skipTemplatesUsedAsLayoutName(
341+
templateFilePaths,
342+
componentsWithLayoutName
343+
);
337344
templateFilePaths = this.skipTemplatesUsedAsPartial(templateFilePaths);
338345
templateFilePaths = this.skipTemplatesUsedInMultipleBackingClasses(templateFilePaths);
339346

340347
this.removeLayoutBinding(templateFilePaths);
341348

342349
if (this.structure === 'flat') {
343350
this.changeComponentStructureToFlat(templateFilePaths);
344-
345351
} else if (this.structure === 'nested') {
346352
this.changeComponentStructureToNested(templateFilePaths);
347-
348353
}
349354

350355
// Clean up
351356
await this.removeEmptyClassicComponentDirectories();
352357
}
353-
}
358+
};
354359

355360
/**
356361
* Determine whether the file path represents an app or an addon
357-
* @param {string} filePathFromApp
362+
* @param {string} filePathFromApp
358363
* @return {'app' | 'addon'}
359364
*/
360365
function typeFromFilePath(filePathFromApp) {
@@ -365,4 +370,4 @@ function typeFromFilePath(filePathFromApp) {
365370
} else {
366371
throw new Error(`invalid file path: ${filePathFromApp}`);
367372
}
368-
}
373+
}

lib/utils/file.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
const fse = require("fs-extra");
2-
const path = require("path");
3-
const removeDirectories = require("remove-empty-directories");
1+
const fse = require('fs-extra');
2+
const path = require('path');
3+
const removeDirectories = require('remove-empty-directories');
44

55
function moveFile(sourceFilePath, targetFilePath) {
66
let targetFileDirectory = path.dirname(targetFilePath);

lib/utils/js-parser.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ const options = {
2323
'dynamicImport',
2424
'nullishCoalescingOperator',
2525
'optionalChaining',
26-
'decorators-legacy'
26+
'decorators-legacy',
2727
],
2828
};
2929

3030
module.exports = {
3131
parse(code) {
3232
return babylon.parse(code, options);
3333
},
34-
};
34+
};

0 commit comments

Comments
 (0)