-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
151 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,33 @@ | ||
const childProcess = require('child_process'); | ||
const { execFileWithInheritedOutput } = require('./util/exec-file'); | ||
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task'); | ||
|
||
module.exports = function(grunt) { | ||
grunt.registerTask('parser', 'Generate jison parser.', function() { | ||
const done = this.async(); | ||
const OUTPUT_FILE = 'lib/handlebars/compiler/parser.js'; | ||
|
||
let cmd = './node_modules/.bin/jison'; | ||
module.exports = function(grunt) { | ||
const registerAsyncTask = createRegisterAsyncTaskFn(grunt); | ||
|
||
if (process.platform === 'win32') { | ||
cmd = 'node_modules\\.bin\\jison.cmd'; | ||
} | ||
registerAsyncTask('parser', async () => { | ||
await runJison(); | ||
combineWithPrefixAndSuffix(); | ||
grunt.log.writeln(`Parser "${OUTPUT_FILE}" created.`); | ||
}); | ||
|
||
const child = childProcess.spawn( | ||
cmd, | ||
['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'], | ||
{ stdio: 'inherit' } | ||
); | ||
child.on('exit', function(code) { | ||
if (code != 0) { | ||
grunt.fatal('Jison failure: ' + code); | ||
done(); | ||
return; | ||
} | ||
async function runJison() { | ||
await execFileWithInheritedOutput('jison', [ | ||
'-m', | ||
'js', | ||
'src/handlebars.yy', | ||
'src/handlebars.l' | ||
]); | ||
} | ||
|
||
const src = [ | ||
'src/parser-prefix.js', | ||
'handlebars.js', | ||
'src/parser-suffix.js' | ||
] | ||
.map(grunt.file.read) | ||
.join(''); | ||
grunt.file.delete('handlebars.js'); | ||
function combineWithPrefixAndSuffix() { | ||
const combinedParserSourceCode = | ||
grunt.file.read('src/parser-prefix.js') + | ||
grunt.file.read('handlebars.js') + | ||
grunt.file.read('src/parser-suffix.js'); | ||
|
||
grunt.file.write('lib/handlebars/compiler/parser.js', src); | ||
grunt.log.writeln('Parser "lib/handlebars/compiler/parser.js" created.'); | ||
done(); | ||
}); | ||
}); | ||
grunt.file.write(OUTPUT_FILE, combinedParserSourceCode); | ||
grunt.file.delete('handlebars.js'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,45 @@ | ||
const childProcess = require('child_process'), | ||
fs = require('fs'), | ||
os = require('os'), | ||
expect = require('chai').expect, | ||
util = require('util'); | ||
|
||
const readFile = util.promisify(fs.readFile); | ||
const execFile = util.promisify(childProcess.execFile); | ||
expect = require('chai').expect; | ||
|
||
module.exports = function(grunt) { | ||
grunt.registerTask( | ||
'test:bin', | ||
wrapAsync(async function() { | ||
const { stdout } = await execFileWithWin32Fallback('./bin/handlebars', [ | ||
'-a', | ||
'spec/artifacts/empty.handlebars' | ||
]); | ||
|
||
const expectedOutput = await readFile( | ||
'./spec/expected/empty.amd.js', | ||
'utf-8' | ||
); | ||
|
||
const normalizedOutput = normalizeCrlf(stdout); | ||
const normalizedExpectedOutput = normalizeCrlf(expectedOutput); | ||
expect(normalizedOutput).to.equal(normalizedExpectedOutput); | ||
}) | ||
); | ||
|
||
async function execFileWithWin32Fallback(command, args) { | ||
grunt.registerTask('test:bin', function() { | ||
const stdout = executeBinHandlebars( | ||
'-a', | ||
'spec/artifacts/empty.handlebars' | ||
); | ||
|
||
const expectedOutput = fs.readFileSync( | ||
'./spec/expected/empty.amd.js', | ||
'utf-8' | ||
); | ||
|
||
const normalizedOutput = normalizeCrlf(stdout); | ||
const normalizedExpectedOutput = normalizeCrlf(expectedOutput); | ||
|
||
expect(normalizedOutput).to.equal(normalizedExpectedOutput); | ||
}); | ||
}; | ||
|
||
// helper functions | ||
|
||
function executeBinHandlebars(...args) { | ||
if (os.platform() === 'win32') { | ||
// On Windows, the executable handlebars.js file cannot be run directly | ||
if (os.platform() === 'win32') { | ||
args.unshift(command); | ||
command = process.argv[0]; | ||
} | ||
return execFile(command, args, { encoding: 'utf-8' }); | ||
const nodeJs = process.argv[0]; | ||
return execFilesSyncUtf8(nodeJs, ['./bin/handlebars'].concat(args)); | ||
} | ||
return execFilesSyncUtf8('./bin/handlebars', args); | ||
} | ||
|
||
function normalizeCrlf(string) { | ||
if (string != null) { | ||
return string.replace(/\r\n/g, '\n'); | ||
} | ||
return string; | ||
} | ||
function execFilesSyncUtf8(command, args) { | ||
return childProcess.execFileSync(command, args, { encoding: 'utf-8' }); | ||
} | ||
|
||
function wrapAsync(asyncFunction) { | ||
return function() { | ||
asyncFunction() | ||
.catch(error => { | ||
grunt.fatal(error); | ||
}) | ||
.finally(this.async()); | ||
}; | ||
function normalizeCrlf(string) { | ||
if (typeof string === 'string') { | ||
return string.replace(/\r\n/g, '\n'); | ||
} | ||
}; | ||
return string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,36 @@ | ||
const childProcess = require('child_process'); | ||
const { execNodeJsScriptWithInheritedOutput } = require('./util/exec-file'); | ||
const { createRegisterAsyncTaskFn } = require('./util/async-grunt-task'); | ||
|
||
module.exports = function(grunt) { | ||
grunt.registerTask( | ||
'test:mocha', | ||
promiseBasedTask(async () => forkAndWait('./spec/env/runner')) | ||
); | ||
const registerAsyncTask = createRegisterAsyncTaskFn(grunt); | ||
|
||
grunt.registerTask( | ||
'test:cov', | ||
promiseBasedTask(async () => | ||
forkAndWait( | ||
'node_modules/istanbul/lib/cli.js', | ||
'cover', | ||
'--source-map', | ||
'--', | ||
'./spec/env/runner.js' | ||
) | ||
) | ||
registerAsyncTask('test:mocha', async () => | ||
execNodeJsScriptWithInheritedOutput('./spec/env/runner') | ||
); | ||
|
||
grunt.registerTask( | ||
'test:min', | ||
promiseBasedTask(async () => forkAndWait('./spec/env/runner', '--min')) | ||
registerAsyncTask('test:cov', async () => | ||
execNodeJsScriptWithInheritedOutput('node_modules/istanbul/lib/cli.js', [ | ||
'cover', | ||
'--source-map', | ||
'--', | ||
'./spec/env/runner.js' | ||
]) | ||
); | ||
|
||
grunt.registerTask( | ||
'test:check-cov', | ||
promiseBasedTask(() => | ||
forkAndWait( | ||
'node_modules/istanbul/lib/cli.js', | ||
'check-coverage', | ||
'--statements', | ||
'100', | ||
'--functions', | ||
'100', | ||
'--branches', | ||
'100', | ||
'--lines 100' | ||
) | ||
) | ||
registerAsyncTask('test:min', async () => | ||
execNodeJsScriptWithInheritedOutput('./spec/env/runner', ['--min']) | ||
); | ||
|
||
function promiseBasedTask(asyncFunction) { | ||
return function() { | ||
asyncFunction() | ||
.catch(error => { | ||
grunt.fatal(error); | ||
}) | ||
.finally(this.async()); | ||
}; | ||
} | ||
|
||
async function forkAndWait(command, ...args) { | ||
return new Promise((resolve, reject) => { | ||
const child = childProcess.fork(command, args, { stdio: 'inherit' }); | ||
child.on('close', code => { | ||
if (code !== 0) { | ||
reject(new Error(`Child process failed with exit-code ${code}`)); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
grunt.registerTask('test', ['test:bin', 'test:cov', 'test:check-cov']); | ||
registerAsyncTask('test:check-cov', async () => | ||
execNodeJsScriptWithInheritedOutput('node_modules/istanbul/lib/cli.js', [ | ||
'check-coverage', | ||
'--statements', | ||
'100', | ||
'--functions', | ||
'100', | ||
'--branches', | ||
'100', | ||
'--lines 100' | ||
]) | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module.exports = { createRegisterAsyncTaskFn }; | ||
|
||
function createRegisterAsyncTaskFn(grunt) { | ||
return function registerAsyncTask(name, asyncFunction) { | ||
grunt.registerTask(name, function() { | ||
asyncFunction() | ||
.catch(error => { | ||
grunt.fatal(error); | ||
}) | ||
.finally(this.async()); | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
const childProcess = require('child_process'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
module.exports = { | ||
execNodeJsScriptWithInheritedOutput, | ||
execFileWithInheritedOutput | ||
}; | ||
|
||
async function execNodeJsScriptWithInheritedOutput(command, args) { | ||
return new Promise((resolve, reject) => { | ||
const child = childProcess.fork(command, args, { stdio: 'inherit' }); | ||
child.on('close', code => { | ||
if (code !== 0) { | ||
reject(new Error(`Child process failed with exit-code ${code}`)); | ||
} | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
|
||
async function execFileWithInheritedOutput(command, args) { | ||
return new Promise((resolve, reject) => { | ||
const resolvedCommand = preferLocalDependencies(command); | ||
const child = childProcess.spawn(resolvedCommand, args, { | ||
stdio: 'inherit' | ||
}); | ||
child.on('exit', code => { | ||
if (code !== 0) { | ||
reject(new Error(`Child process failed with exit-code ${code}`)); | ||
} | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
|
||
function preferLocalDependencies(command) { | ||
const localCandidate = resolveLocalCandidate(command); | ||
|
||
if (fs.existsSync(localCandidate)) { | ||
return localCandidate; | ||
} | ||
return command; | ||
} | ||
|
||
function resolveLocalCandidate(command) { | ||
if (process.platform === 'win32') { | ||
return path.join('node_modules', '.bin', command + '.cmd'); | ||
} | ||
return path.join('node_modules', '.bin', command); | ||
} |