Skip to content

Commit 7995cbf

Browse files
committed
Add generator for template transforms and tests
1 parent c809c5d commit 7995cbf

3 files changed

Lines changed: 235 additions & 9 deletions

File tree

commands/local/generate/codemod.js

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ module.exports.command = 'codemod <codemod-name>';
22
module.exports.desc = 'Generate a new codemod file';
33

44
module.exports.builder = function builder(yargs) {
5-
yargs.positional('codemod-name', {
6-
describe: 'the name of the codemod to generate',
7-
});
5+
yargs
6+
.positional('codemod-name', {
7+
describe: 'the name of the codemod to generate',
8+
})
9+
.option('type', {
10+
alias: 't',
11+
describe: 'choose the transform type',
12+
choices: ['js', 'hbs'],
13+
default: 'js',
14+
});
815
};
916

10-
module.exports.handler = function handler(options) {
17+
function jsHandler(options) {
1118
const fs = require('fs-extra');
1219
const { stripIndent } = require('common-tags');
1320
const importCwd = require('import-cwd');
@@ -86,5 +93,92 @@ module.exports.handler = function handler(options) {
8693
'utf8'
8794
);
8895

89-
generateFixture({ codemodName, fixtureName: 'basic' });
96+
generateFixture({ codemodName, fixtureName: 'basic', type: options.type });
97+
}
98+
99+
function hbsHandler(options) {
100+
const fs = require('fs-extra');
101+
const { stripIndent } = require('common-tags');
102+
const importCwd = require('import-cwd');
103+
const generateFixture = require('./fixture').handler;
104+
105+
let { codemodName } = options;
106+
let projectName = importCwd('./package.json').name;
107+
let codemodDir = `${process.cwd()}/transforms/${codemodName}`;
108+
109+
fs.outputFileSync(
110+
`${codemodDir}/index.js`,
111+
stripIndent`
112+
module.exports = function ({ source /*, path*/ }, { parse, visit }) {
113+
const ast = parse(source);
114+
115+
return visit(ast, (env) => {
116+
let { builders: b } = env.syntax;
117+
118+
return {
119+
MustacheStatement() {
120+
return b.mustache(b.path('wat-wat'));
121+
},
122+
};
123+
});
124+
};
125+
`,
126+
'utf8'
127+
);
128+
fs.outputFileSync(
129+
`${codemodDir}/test.js`,
130+
stripIndent`
131+
'use strict';
132+
133+
const { runTransformTest } = require('codemod-cli');
134+
135+
runTransformTest({
136+
type: 'template',
137+
name: '${codemodName}',
138+
});
139+
`,
140+
'utf8'
141+
);
142+
fs.outputFileSync(
143+
`${codemodDir}/README.md`,
144+
stripIndent`
145+
# ${codemodName}\n
146+
147+
## Usage
148+
149+
\`\`\`
150+
npx ${projectName} ${codemodName} path/of/files/ or/some**/*glob.hbs
151+
152+
# or
153+
154+
yarn global add ${projectName}
155+
${projectName} ${codemodName} path/of/files/ or/some**/*glob.hbs
156+
\`\`\`
157+
158+
## Local Usage
159+
\`\`\`
160+
node ./bin/cli.js ${codemodName} path/of/files/ or/some**/*glob.hbs
161+
\`\`\`
162+
163+
## Input / Output
164+
165+
<!--FIXTURES_TOC_START-->
166+
<!--FIXTURES_TOC_END-->
167+
168+
<!--FIXTURES_CONTENT_START-->
169+
<!--FIXTURES_CONTENT_END-->
170+
`,
171+
'utf8'
172+
);
173+
174+
generateFixture({ codemodName, fixtureName: 'basic', type: options.type });
175+
}
176+
177+
module.exports.handler = function handler(options) {
178+
switch (options.type) {
179+
case 'js':
180+
return jsHandler(options);
181+
case 'hbs':
182+
return hbsHandler(options);
183+
}
90184
};

commands/local/generate/fixture.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ module.exports.builder = function builder(yargs) {
88
})
99
.positional('fixture-name', {
1010
describe: 'the name of the fixture to generate',
11+
})
12+
.option('type', {
13+
alias: 't',
14+
describe: 'choose the fixture type',
15+
choices: ['js', 'hbs'],
16+
default: 'js',
1117
});
1218
};
1319

@@ -18,6 +24,6 @@ module.exports.handler = function handler(options) {
1824
let codemodDir = `${process.cwd()}/transforms/${codemodName}`;
1925
let fixturePath = `${codemodDir}/__testfixtures__/${fixtureName}`;
2026

21-
fs.outputFileSync(`${fixturePath}.input.js`, '');
22-
fs.outputFileSync(`${fixturePath}.output.js`, '');
27+
fs.outputFileSync(`${fixturePath}.input.${options.type}`, '');
28+
fs.outputFileSync(`${fixturePath}.output.${options.type}`, '');
2329
};

tests/cli-test.js

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ QUnit.module('codemod-cli', function(hooks) {
112112
setupProject(hooks);
113113

114114
QUnit.module('codemod', function() {
115-
QUnit.test('should generate a codemod', async function(assert) {
115+
QUnit.test('should generate a js codemod', async function(assert) {
116116
let result = await execa(EXECUTABLE_PATH, ['generate', 'codemod', 'main']);
117117

118118
assert.equal(result.exitCode, 0, 'exited with zero');
@@ -127,10 +127,26 @@ QUnit.module('codemod-cli', function(hooks) {
127127
'main/test.js',
128128
]);
129129
});
130+
131+
QUnit.test('should generate a hbs codemod', async function(assert) {
132+
let result = await execa(EXECUTABLE_PATH, ['generate', 'codemod', 'main', '--type', 'hbs']);
133+
134+
assert.equal(result.exitCode, 0, 'exited with zero');
135+
assert.deepEqual(walkSync(codemodProject.path('transforms')), [
136+
'.gitkeep',
137+
'main/',
138+
'main/README.md',
139+
'main/__testfixtures__/',
140+
'main/__testfixtures__/basic.input.hbs',
141+
'main/__testfixtures__/basic.output.hbs',
142+
'main/index.js',
143+
'main/test.js',
144+
]);
145+
});
130146
});
131147

132148
QUnit.module('fixture', function() {
133-
QUnit.test('should generate a fixture for the specified codemod', async function(assert) {
149+
QUnit.test('should generate a fixture for the specified js codemod', async function(assert) {
134150
await execa(EXECUTABLE_PATH, ['generate', 'codemod', 'main']);
135151
let result = await execa(EXECUTABLE_PATH, [
136152
'generate',
@@ -153,6 +169,32 @@ QUnit.module('codemod-cli', function(hooks) {
153169
'main/test.js',
154170
]);
155171
});
172+
173+
QUnit.test('should generate a fixture for the specified hbs codemod', async function(assert) {
174+
await execa(EXECUTABLE_PATH, ['generate', 'codemod', 'main', '--type', 'hbs']);
175+
let result = await execa(EXECUTABLE_PATH, [
176+
'generate',
177+
'fixture',
178+
'main',
179+
'this-dot-owner',
180+
'--type',
181+
'hbs',
182+
]);
183+
184+
assert.equal(result.exitCode, 0, 'exited with zero');
185+
assert.deepEqual(walkSync(codemodProject.path('transforms')), [
186+
'.gitkeep',
187+
'main/',
188+
'main/README.md',
189+
'main/__testfixtures__/',
190+
'main/__testfixtures__/basic.input.hbs',
191+
'main/__testfixtures__/basic.output.hbs',
192+
'main/__testfixtures__/this-dot-owner.input.hbs',
193+
'main/__testfixtures__/this-dot-owner.output.hbs',
194+
'main/index.js',
195+
'main/test.js',
196+
]);
197+
});
156198
});
157199

158200
QUnit.module('test', function() {
@@ -539,5 +581,89 @@ QUnit.module('codemod-cli', function(hooks) {
539581
});
540582
});
541583
});
584+
585+
QUnit.module('runTransform type=template', function(hooks) {
586+
let userProject;
587+
588+
hooks.beforeEach(async function() {
589+
// includes simple mustache transform
590+
await execa(EXECUTABLE_PATH, ['generate', 'codemod', 'main', '--type', 'hbs']);
591+
592+
userProject = await createTempDir();
593+
process.chdir(userProject.path());
594+
});
595+
596+
hooks.afterEach(function() {
597+
process.chdir(ROOT);
598+
599+
return userProject.dispose();
600+
});
601+
602+
QUnit.test('runs transform', async function(assert) {
603+
userProject.write({
604+
foo: {
605+
'something.hbs': '{{what}}',
606+
'other.hbs': '{{what}}',
607+
},
608+
});
609+
610+
await CodemodCLI.runTransform(
611+
codemodProject.path('bin'),
612+
'main',
613+
'foo/*thing.hbs',
614+
undefined,
615+
'template'
616+
);
617+
618+
assert.deepEqual(userProject.read(), {
619+
foo: {
620+
'something.hbs': '{{wat-wat}}',
621+
'other.hbs': '{{what}}',
622+
},
623+
});
624+
});
625+
626+
QUnit.test('runs transform with options', async function(assert) {
627+
codemodProject.write({
628+
transforms: {
629+
main: {
630+
'index.js': `
631+
const { getOptions } = require('codemod-cli');
632+
module.exports = function ({ source /*, path*/ }, { parse, visit }) {
633+
const ast = parse(source);
634+
const options = getOptions();
635+
636+
return visit(ast, (env) => {
637+
let { builders: b } = env.syntax;
638+
639+
return {
640+
MustacheStatement() {
641+
return b.mustache(b.path(options.biz + options.baz));
642+
},
643+
};
644+
});
645+
};
646+
`,
647+
},
648+
},
649+
});
650+
651+
userProject.write({
652+
foo: { 'something.hbs': `{{foo}}` },
653+
});
654+
655+
await CodemodCLI.runTransform(
656+
codemodProject.path('bin'),
657+
'main',
658+
['--biz', 'A', '--baz', 'B', 'foo/*ing.hbs'],
659+
undefined,
660+
'template'
661+
);
662+
663+
assert.deepEqual(userProject.read(), {
664+
foo: { 'something.hbs': `{{AB}}` },
665+
});
666+
});
667+
});
542668
});
543669
});

0 commit comments

Comments
 (0)