Skip to content

Commit 3a5b65e

Browse files
committedDec 14, 2019
test/style: refactor parser task
1 parent dde108e commit 3a5b65e

File tree

5 files changed

+151
-133
lines changed

5 files changed

+151
-133
lines changed
 

‎tasks/parser.js

+26-32
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,33 @@
1-
const childProcess = require('child_process');
1+
const { execFileWithInheritedOutput } = require('./util/exec-file');
2+
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task');
23

3-
module.exports = function(grunt) {
4-
grunt.registerTask('parser', 'Generate jison parser.', function() {
5-
const done = this.async();
4+
const OUTPUT_FILE = 'lib/handlebars/compiler/parser.js';
65

7-
let cmd = './node_modules/.bin/jison';
6+
module.exports = function(grunt) {
7+
const registerAsyncTask = createRegisterAsyncTaskFn(grunt);
88

9-
if (process.platform === 'win32') {
10-
cmd = 'node_modules\\.bin\\jison.cmd';
11-
}
9+
registerAsyncTask('parser', async () => {
10+
await runJison();
11+
combineWithPrefixAndSuffix();
12+
grunt.log.writeln(`Parser "${OUTPUT_FILE}" created.`);
13+
});
1214

13-
const child = childProcess.spawn(
14-
cmd,
15-
['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'],
16-
{ stdio: 'inherit' }
17-
);
18-
child.on('exit', function(code) {
19-
if (code != 0) {
20-
grunt.fatal('Jison failure: ' + code);
21-
done();
22-
return;
23-
}
15+
async function runJison() {
16+
await execFileWithInheritedOutput('jison', [
17+
'-m',
18+
'js',
19+
'src/handlebars.yy',
20+
'src/handlebars.l'
21+
]);
22+
}
2423

25-
const src = [
26-
'src/parser-prefix.js',
27-
'handlebars.js',
28-
'src/parser-suffix.js'
29-
]
30-
.map(grunt.file.read)
31-
.join('');
32-
grunt.file.delete('handlebars.js');
24+
function combineWithPrefixAndSuffix() {
25+
const combinedParserSourceCode =
26+
grunt.file.read('src/parser-prefix.js') +
27+
grunt.file.read('handlebars.js') +
28+
grunt.file.read('src/parser-suffix.js');
3329

34-
grunt.file.write('lib/handlebars/compiler/parser.js', src);
35-
grunt.log.writeln('Parser "lib/handlebars/compiler/parser.js" created.');
36-
done();
37-
});
38-
});
30+
grunt.file.write(OUTPUT_FILE, combinedParserSourceCode);
31+
grunt.file.delete('handlebars.js');
32+
}
3933
};

‎tasks/test-bin.js

+35-45
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,45 @@
11
const childProcess = require('child_process'),
22
fs = require('fs'),
33
os = require('os'),
4-
expect = require('chai').expect,
5-
util = require('util');
6-
7-
const readFile = util.promisify(fs.readFile);
8-
const execFile = util.promisify(childProcess.execFile);
4+
expect = require('chai').expect;
95

106
module.exports = function(grunt) {
11-
grunt.registerTask(
12-
'test:bin',
13-
wrapAsync(async function() {
14-
const { stdout } = await execFileWithWin32Fallback('./bin/handlebars', [
15-
'-a',
16-
'spec/artifacts/empty.handlebars'
17-
]);
18-
19-
const expectedOutput = await readFile(
20-
'./spec/expected/empty.amd.js',
21-
'utf-8'
22-
);
23-
24-
const normalizedOutput = normalizeCrlf(stdout);
25-
const normalizedExpectedOutput = normalizeCrlf(expectedOutput);
26-
expect(normalizedOutput).to.equal(normalizedExpectedOutput);
27-
})
28-
);
29-
30-
async function execFileWithWin32Fallback(command, args) {
7+
grunt.registerTask('test:bin', function() {
8+
const stdout = executeBinHandlebars(
9+
'-a',
10+
'spec/artifacts/empty.handlebars'
11+
);
12+
13+
const expectedOutput = fs.readFileSync(
14+
'./spec/expected/empty.amd.js',
15+
'utf-8'
16+
);
17+
18+
const normalizedOutput = normalizeCrlf(stdout);
19+
const normalizedExpectedOutput = normalizeCrlf(expectedOutput);
20+
21+
expect(normalizedOutput).to.equal(normalizedExpectedOutput);
22+
});
23+
};
24+
25+
// helper functions
26+
27+
function executeBinHandlebars(...args) {
28+
if (os.platform() === 'win32') {
3129
// On Windows, the executable handlebars.js file cannot be run directly
32-
if (os.platform() === 'win32') {
33-
args.unshift(command);
34-
command = process.argv[0];
35-
}
36-
return execFile(command, args, { encoding: 'utf-8' });
30+
const nodeJs = process.argv[0];
31+
return execFilesSyncUtf8(nodeJs, ['./bin/handlebars'].concat(args));
3732
}
33+
return execFilesSyncUtf8('./bin/handlebars', args);
34+
}
3835

39-
function normalizeCrlf(string) {
40-
if (string != null) {
41-
return string.replace(/\r\n/g, '\n');
42-
}
43-
return string;
44-
}
36+
function execFilesSyncUtf8(command, args) {
37+
return childProcess.execFileSync(command, args, { encoding: 'utf-8' });
38+
}
4539

46-
function wrapAsync(asyncFunction) {
47-
return function() {
48-
asyncFunction()
49-
.catch(error => {
50-
grunt.fatal(error);
51-
})
52-
.finally(this.async());
53-
};
40+
function normalizeCrlf(string) {
41+
if (typeof string === 'string') {
42+
return string.replace(/\r\n/g, '\n');
5443
}
55-
};
44+
return string;
45+
}

‎tasks/test-mocha.js

+26-56
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,36 @@
1-
const childProcess = require('child_process');
1+
const { execNodeJsScriptWithInheritedOutput } = require('./util/exec-file');
2+
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task');
23

34
module.exports = function(grunt) {
4-
grunt.registerTask(
5-
'test:mocha',
6-
promiseBasedTask(async () => forkAndWait('./spec/env/runner'))
7-
);
5+
const registerAsyncTask = createRegisterAsyncTaskFn(grunt);
86

9-
grunt.registerTask(
10-
'test:cov',
11-
promiseBasedTask(async () =>
12-
forkAndWait(
13-
'node_modules/istanbul/lib/cli.js',
14-
'cover',
15-
'--source-map',
16-
'--',
17-
'./spec/env/runner.js'
18-
)
19-
)
7+
registerAsyncTask('test:mocha', async () =>
8+
execNodeJsScriptWithInheritedOutput('./spec/env/runner')
209
);
2110

22-
grunt.registerTask(
23-
'test:min',
24-
promiseBasedTask(async () => forkAndWait('./spec/env/runner', '--min'))
11+
registerAsyncTask('test:cov', async () =>
12+
execNodeJsScriptWithInheritedOutput('node_modules/istanbul/lib/cli.js', [
13+
'cover',
14+
'--source-map',
15+
'--',
16+
'./spec/env/runner.js'
17+
])
2518
);
2619

27-
grunt.registerTask(
28-
'test:check-cov',
29-
promiseBasedTask(() =>
30-
forkAndWait(
31-
'node_modules/istanbul/lib/cli.js',
32-
'check-coverage',
33-
'--statements',
34-
'100',
35-
'--functions',
36-
'100',
37-
'--branches',
38-
'100',
39-
'--lines 100'
40-
)
41-
)
20+
registerAsyncTask('test:min', async () =>
21+
execNodeJsScriptWithInheritedOutput('./spec/env/runner', ['--min'])
4222
);
4323

44-
function promiseBasedTask(asyncFunction) {
45-
return function() {
46-
asyncFunction()
47-
.catch(error => {
48-
grunt.fatal(error);
49-
})
50-
.finally(this.async());
51-
};
52-
}
53-
54-
async function forkAndWait(command, ...args) {
55-
return new Promise((resolve, reject) => {
56-
const child = childProcess.fork(command, args, { stdio: 'inherit' });
57-
child.on('close', code => {
58-
if (code !== 0) {
59-
reject(new Error(`Child process failed with exit-code ${code}`));
60-
}
61-
});
62-
});
63-
}
64-
65-
grunt.registerTask('test', ['test:bin', 'test:cov', 'test:check-cov']);
24+
registerAsyncTask('test:check-cov', async () =>
25+
execNodeJsScriptWithInheritedOutput('node_modules/istanbul/lib/cli.js', [
26+
'check-coverage',
27+
'--statements',
28+
'100',
29+
'--functions',
30+
'100',
31+
'--branches',
32+
'100',
33+
'--lines 100'
34+
])
35+
);
6636
};

‎tasks/util/async-grunt-task.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = { createRegisterAsyncTaskFn };
2+
3+
function createRegisterAsyncTaskFn(grunt) {
4+
return function registerAsyncTask(name, asyncFunction) {
5+
grunt.registerTask(name, function() {
6+
asyncFunction()
7+
.catch(error => {
8+
grunt.fatal(error);
9+
})
10+
.finally(this.async());
11+
});
12+
};
13+
}

‎tasks/util/exec-file.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const childProcess = require('child_process');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
module.exports = {
6+
execNodeJsScriptWithInheritedOutput,
7+
execFileWithInheritedOutput
8+
};
9+
10+
async function execNodeJsScriptWithInheritedOutput(command, args) {
11+
return new Promise((resolve, reject) => {
12+
const child = childProcess.fork(command, args, { stdio: 'inherit' });
13+
child.on('close', code => {
14+
if (code !== 0) {
15+
reject(new Error(`Child process failed with exit-code ${code}`));
16+
}
17+
resolve();
18+
});
19+
});
20+
}
21+
22+
async function execFileWithInheritedOutput(command, args) {
23+
return new Promise((resolve, reject) => {
24+
const resolvedCommand = preferLocalDependencies(command);
25+
const child = childProcess.spawn(resolvedCommand, args, {
26+
stdio: 'inherit'
27+
});
28+
child.on('exit', code => {
29+
if (code !== 0) {
30+
reject(new Error(`Child process failed with exit-code ${code}`));
31+
}
32+
resolve();
33+
});
34+
});
35+
}
36+
37+
function preferLocalDependencies(command) {
38+
const localCandidate = resolveLocalCandidate(command);
39+
40+
if (fs.existsSync(localCandidate)) {
41+
return localCandidate;
42+
}
43+
return command;
44+
}
45+
46+
function resolveLocalCandidate(command) {
47+
if (process.platform === 'win32') {
48+
return path.join('node_modules', '.bin', command + '.cmd');
49+
}
50+
return path.join('node_modules', '.bin', command);
51+
}

0 commit comments

Comments
 (0)
Please sign in to comment.