Skip to content

Commit

Permalink
Merge pull request #64 from davidchambers/transcribe
Browse files Browse the repository at this point in the history
add "prefix" option for Transcribe compatibility
  • Loading branch information
davidchambers committed Oct 13, 2015
2 parents 520dd0d + 8066d6a commit 4981726
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 44 deletions.
4 changes: 3 additions & 1 deletion lib/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ program
.version(pkg.version)
.usage('[options] path/to/js/or/coffee/module')
.option('-m, --module <type>', 'specify module system ("amd" or "commonjs")')
.option(' --nodejs', 'pass options directly to the "node" binary')
.option(' --nodejs <options>', 'pass options directly to the "node" binary')
.option(' --prefix <prefix>', 'specify Transcribe-style prefix (e.g. ".")')
.option('-p, --print', 'output the rewritten source without running tests')
.option('-s, --silent', 'suppress output')
.option('-t, --type <type>', 'specify file type ("coffee" or "js")')
Expand All @@ -22,6 +23,7 @@ program

var validators = {
module: R.contains(R.__, [undefined, 'amd', 'commonjs']),
prefix: R.T,
print: R.T,
silent: R.T,
type: R.contains(R.__, [undefined, 'coffee', 'js'])
Expand Down
104 changes: 61 additions & 43 deletions lib/doctest.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
return match[1];
}());

var prefix = R.defaultTo('', options.prefix);

return fetch(path, options, function(text) {
var source = toModule(rewrite(text, type), options.module);
var source = toModule(rewrite(type, prefix, text), options.module);

if (options.print) {
if (!options.silent) {
Expand Down Expand Up @@ -99,6 +101,13 @@
// joinLines :: [String] -> String
var joinLines = R.join('\n');

// matchLine :: String -> String -> (String,String,String)?
var matchLine = R.curry(function(prefix, s) {
return startsWith(prefix, s) ?
R.match(/^\s*(>|[.]*)[ ]?(.*)$/, R.drop(prefix.length, s)) :
null;
});

// noop :: * -> ()
var noop = function() {};

Expand All @@ -110,6 +119,10 @@
// reduce :: a -> (a,b,Number,[b] -> a) -> [b] -> a
var reduce = R.flip(R.addIndex(R.reduce));

// startsWith :: String -> String -> Boolean
var startsWith = R.curry(function(prefix, s) {
return R.take(prefix.length, s) === prefix;
});

// unlines :: [String] -> String
var unlines = R.compose(R.join(''), R.map(R.concat(R.__, '\n')));
Expand All @@ -133,8 +146,9 @@
};


var rewrite = function(input, type) {
return rewrite[type](input.replace(/\r\n?/g, '\n').replace(/^#!.*/, ''));
var rewrite = function(type, prefix, input) {
return rewrite[type](prefix,
input.replace(/\r\n?/g, '\n').replace(/^#!.*/, ''));
};


Expand Down Expand Up @@ -225,32 +239,32 @@
_2._last.input.value = R.compose(_2._last.input, _value);


// transformComments :: [Object] -> [Object]
// transformComments :: String -> [Object] -> [Object]
//
// Returns a list of {input,output} pairs representing the doctests
// present in the given list of esprima comment objects.
//
// > transformComments([{
// . type: 'Line',
// . value: ' > 6 * 7',
// . loc: {start: {line: 1, column: 0}, end: {line: 1, column: 10}}
// . }, {
// . type: 'Line',
// . value: ' 42',
// . loc: {start: {line: 2, column: 0}, end: {line: 2, column: 5}}
// . }])
// [{
// . commentIndex: 1,
// . '!': false,
// . input: {
// . value: '6 * 7',
// . loc: {start: {line: 1, column: 0}, end: {line: 1, column: 10}}},
// . output: {
// . value: '42',
// . loc: {start: {line: 2, column: 0}, end: {line: 2, column: 5}}}
// . }]
var transformComments = R.pipe(
reduce(['default', []], function(accum, comment, commentIndex) {
// > transformComments('', [{
// . type: 'Line',
// . value: ' > 6 * 7',
// . loc: {start: {line: 1, column: 0}, end: {line: 1, column: 10}}
// . }, {
// . type: 'Line',
// . value: ' 42',
// . loc: {start: {line: 2, column: 0}, end: {line: 2, column: 5}}
// . }])
// [{
// . commentIndex: 1,
// . '!': false,
// . input: {
// . value: '6 * 7',
// . loc: {start: {line: 1, column: 0}, end: {line: 1, column: 10}}},
// . output: {
// . value: '42',
// . loc: {start: {line: 2, column: 0}, end: {line: 2, column: 5}}}
// . }]
var transformComments = R.curry(function(prefix, comments) {
var gather = function(accum, comment, commentIndex) {
return R.pipe(
R.prop('value'),
R.split('\n'),
Expand All @@ -265,8 +279,10 @@
end = comment.loc.end;
}

var match = R.match(/^(>|[.]*)[ ]?(.*)$/, normalizedLine);
var match = matchLine(prefix, normalizedLine);
return (
match == null ?
R.identity :
match[1] === '>' ?
R.pipe(R.set(_1, 'input'),
R.over(_2, R.append({})),
Expand All @@ -288,10 +304,11 @@
)(accum);
})
)(comment);
}),
R.last,
R.map(normalizeTest)
);
};

return R.map(normalizeTest,
R.nth(1, reduce(['default', []], gather, comments)));
});


// substring :: String,{line,column},{line,column} -> String
Expand Down Expand Up @@ -387,7 +404,7 @@
};


rewrite.js = function(input) {
rewrite.js = function(prefix, input) {
// 1. Locate block comments and line comments within the input text.
//
// 2. Create a list of comment chunks from the list of line comments
Expand Down Expand Up @@ -423,7 +440,7 @@
var tests = R.pipe(
getComments,
R.partition(R.propEq('type', 'Block')),
R.map(transformComments),
R.map(transformComments(prefix)),
R.zipObj(['blockTests', 'lineTests'])
)(input);

Expand Down Expand Up @@ -462,7 +479,7 @@
)(source);
};

rewrite.coffee = function(input) {
rewrite.coffee = function(prefix, input) {
var chunks = R.pipe(
R.match(/^.*(?=\n)/gm),
R.addIndex(R.reduce)(function(accum, line, idx) {
Expand All @@ -484,28 +501,29 @@
R.zipObj(['literalChunks', 'commentChunks'])
)(input);

var matchLine = R.match(/^([ \t]*)#[ \t]*(>|[.]*)[ ]?(.*)$/);
var matchFullLine = R.match(/^([ \t]*)#[ \t]*(.*)$/);
var testChunks = R.map(R.pipe(
function(commentChunk) {
return R.pipe(
R.prop('lines'),
reduce(['default', []], function(accum, line, idx) {
var state = accum[0];
var tests = accum[1];
var match = R.tail(matchLine(line));
var indent = match[0];
var prefix = match[1];
var value = match[2];
if (prefix === '>') {
tests[tests.length] = {indent: indent, input: {value: value}};
var fullMatch = matchFullLine(line);
var indent = fullMatch[1];
var match = matchLine(prefix, fullMatch[2]);
if (match == null) {
return accum;
} else if (match[1] === '>') {
tests[tests.length] = {indent: indent, input: {value: match[2]}};
return ['input', tests];
} else if (prefix) {
tests[tests.length - 1][state].value += '\n' + value;
} else if (match[1]) {
tests[tests.length - 1][state].value += '\n' + match[2];
return [state, tests];
} else if (state === 'input') {
tests[tests.length - 1].output = {
loc: {start: {line: commentChunk.loc.start.line + idx}},
value: value
value: match[2]
};
return ['output', tests];
} else {
Expand Down
2 changes: 2 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ testModule('test/line-endings/CR+LF.coffee');
testModule('test/line-endings/LF.js');
testModule('test/line-endings/LF.coffee');
testModule('test/exceptions/index.js');
testModule('test/transcribe/index.js', {prefix: '.'});
testModule('test/transcribe/index.coffee', {prefix: '.'});
testModule('test/amd/index.js', {module: 'amd'});
testModule('test/commonjs/require/index.js', {module: 'commonjs'});
testModule('test/commonjs/exports/index.js', {module: 'commonjs'});
Expand Down
10 changes: 10 additions & 0 deletions test/transcribe/index.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#% map :: (a -> b) -> [a] -> [b]
#.
#. Transforms a list of elements of type `a` into a list of elements
#. of type `b` using the provided function of type `a -> b`.
#.
#. ```coffee
#. > map(Math.sqrt)([1, 4, 9])
#. [1, 2, 3]
#. ```
map = (f) -> (xs) -> f x for x in xs
18 changes: 18 additions & 0 deletions test/transcribe/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//# map :: (a -> b) -> [a] -> [b]
//.
//. Transforms a list of elements of type `a` into a list of elements
//. of type `b` using the provided function of type `a -> b`.
//.
//. ```javascript
//. > map(Math.sqrt)([1, 4, 9])
//. [1, 2, 3]
//. ```
var map = function(f) {
return function(xs) {
var output = [];
for (var idx = 0; idx < xs.length; idx += 1) {
output.push(f(xs[idx]));
}
return output;
};
};
4 changes: 4 additions & 0 deletions test/transcribe/results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = [[
'accepts Transcribe-style prefix',
[true, '[1, 2, 3]', '[1, 2, 3]', 8]
]];

0 comments on commit 4981726

Please # to comment.