Skip to content

Commit

Permalink
Merge pull request gajus#166 from jedwards1211/convert-option
Browse files Browse the repository at this point in the history
feat(pragma): add optInOnly option
  • Loading branch information
phpnode authored Dec 6, 2017
2 parents bda1474 + 88952ae commit 123aa74
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default class ConversionContext {
shouldAssert: boolean = true;
shouldWarn: boolean = false;
shouldAnnotate: boolean = true;
optInOnly: boolean = false;
isAnnotating: boolean = false;
suppressCommentPatterns: RegExp[] = [/\$FlowFixMe/];
suppressTypeNames: string[] = ['$FlowFixMe'];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* @flow */

import testTransform from './testTransform';

describe('optInOnly', () => {
it("transforms files with @flow-runtime annotation", () => {
const input = `
/* @flow */
/* @flow-runtime enable */
type Demo = 123;
("nope": Demo);
const demo = ([foo]: string[]): string => foo;
`;

const expected = `
import t from "flow-runtime";
/* @flow */
/* @flow-runtime enable */
const Demo = t.type("Demo", t.number(123));
let _undefinedType = Demo;
"nope";
const demo = (_arg) => {
let [foo] = _arg;
return foo;
};
`;

testTransform(input, {annotate: false, assert: false, optInOnly: true}, expected);
});
it("doesn't transform files without @flow-runtime annotation", () => {
const input = `
/* @flow */
const Demo = 123;
`;

const expected = `
/* @flow */
const Demo = 123;
`;

testTransform(input, {optInOnly: true}, expected);
})
});
76 changes: 76 additions & 0 deletions packages/babel-plugin-flow-runtime/src/__tests__/testTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* @flow */

import {equal} from 'assert';

import fixtures from './fixtures';

import transform from '../transform';

import * as babylon from 'babylon';
import generate from 'babel-generator';
import traverse from 'babel-traverse';
import type {Node, NodePath} from 'babel-traverse';

import type {Options} from '../createConversionContext';

function stripFlowTypes (program: Node): Node {
traverse(program, {
Flow (path: NodePath) {
path.remove();
},
TypeCastExpression(path) {
let { node } = path;
do {
node = node.expression;
} while (node.type === 'TypeCastExpression');
path.replaceWith(node);
},
Class(path) {
path.node.implements = null;
}
});
return program;
}

function parse (source: string): Node {
return babylon.parse(source, {
filename: 'unknown',
sourceType: 'module',
plugins: [
'jsx',
'flow',
'doExpressions',
'objectRestSpread',
'decorators',
'classProperties',
'exportExtensions',
'asyncGenerators',
'functionBind',
'functionSent'
]
});
}

function normalize (input: string): string {
return input
.trim()
.replace(/\s+/g, ' ')
.replace(/\(\s+/g, '(')
.replace(/\s+\)/g, ')')
.replace(/\{\s+/g, '{\n')
.replace(/\s+\}/g, '\n}')
.replace(/\[\s+/g, '[')
.replace(/\s+]/g, ']')
.replace(/\}\s+([A-Za-z])/g, '\n}\n$1')
.split(';')
.join(';\n')
.trim()
;
}

export default function testTransform(input: string, options: Options, expected: string) {
const parsed = parse(input);
const transformed = stripFlowTypes(transform(parsed, options));
const generated = generate(transformed).code;
equal(normalize(generated), normalize(expected));
}
90 changes: 4 additions & 86 deletions packages/babel-plugin-flow-runtime/src/__tests__/transform.test.js
Original file line number Diff line number Diff line change
@@ -1,105 +1,23 @@
/* @flow */

import {equal} from 'assert';

import fixtures from './fixtures';

import transform from '../transform';

import * as babylon from 'babylon';
import generate from 'babel-generator';
import traverse from 'babel-traverse';
import type {Node, NodePath} from 'babel-traverse';

import testTransform from './testTransform';

describe('transform', () => {
for (const [name, {input, expected, annotated, combined}] of fixtures) {
it(`should transform ${name}`, () => {
const parsed = parse(input);
const transformed = stripFlowTypes(transform(parsed, {
assert: true,
annotate: false
}));
const generated = generate(transformed).code;
equal(normalize(generated), normalize(expected));
testTransform(input, {assert: true, annotate: false}, expected);
});
if (annotated) {
it(`should transform ${name} with decorations`, () => {
const parsed = parse(input);
const transformed = stripFlowTypes(transform(parsed, {
assert: false,
annotate: true
}));
const generated = generate(transformed).code;
equal(normalize(generated), normalize(annotated));
testTransform(input, {assert: false, annotate: true}, annotated);
});
}
if (combined) {
it(`should transform ${name} with decorations and assertions`, () => {
const parsed = parse(input);
const transformed = stripFlowTypes(transform(parsed, {
assert: true,
annotate: true
}));
const generated = generate(transformed).code;
equal(normalize(generated), normalize(combined));
testTransform(input, {assert: true, annotate: true}, combined);
});
}
}
});


function stripFlowTypes (program: Node): Node {
traverse(program, {
Flow (path: NodePath) {
path.remove();
},
TypeCastExpression(path) {
let { node } = path;
do {
node = node.expression;
} while (node.type === 'TypeCastExpression');
path.replaceWith(node);
},
Class(path) {
path.node.implements = null;
}
});
return program;
}

function parse (source: string): Node {
return babylon.parse(source, {
filename: 'unknown',
sourceType: 'module',
plugins: [
'jsx',
'flow',
'doExpressions',
'objectRestSpread',
'decorators',
'classProperties',
'exportExtensions',
'asyncGenerators',
'functionBind',
'functionSent'
]
});
}

function normalize (input: string): string {
return input
.trim()
.replace(/\s+/g, ' ')
.replace(/\(\s+/g, '(')
.replace(/\s+\)/g, ')')
.replace(/\{\s+/g, '{\n')
.replace(/\s+\}/g, '\n}')
.replace(/\[\s+/g, '[')
.replace(/\s+]/g, ']')
.replace(/\}\s+([A-Za-z])/g, '\n}\n$1')
.split(';')
.join(';\n')
.trim()
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function collectProgramOptions (context: ConversionContext, node:
const options = collectOptionsFromPragma(context, node);
if (!options) {
// if we have no options, check to see whether flow is in use in this file
return hasFlowNodes(node);
return !context.optInOnly && hasFlowNodes(node);
}
else if (options.ignore) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default function createConversionContext (options: Options): ConversionCo

const context = new ConversionContext();

context.optInOnly = options.optInOnly ? true : false;

context.shouldAssert = options.assert === undefined
? process.env.NODE_ENV === 'development'
: Boolean(options.assert)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export default class BabelPluginFlowRuntimePage extends Component {
<li><code>assert</code> - Boolean, indicates whether types should be asserted at runtime. Defaults to <code>true</code> if <code>process.env.NODE_ENV === 'development'</code>, otherwise <code>false</code>.</li>
<li><code>warn</code> - Boolean, if <code>true</code> flow-runtime will emit warnings instead of throwing in case of a failing check. This can be very useful when first introducing types to a codebase.</li>
<li><code>annotate</code> - Boolean, indicates whether object or function values that have type annotations should be annotated with those types at runtime. Defaults to <code>true</code>.</li>
<li><code>optInOnly</code> - Boolean, if <code>true</code>, ignores all files that don't have a <code>@flow-runtime</code> annotation. To re-enable <code>babel-plugin-flow-runtime</code> for a particular file with the same options as the plugin, annotate it with <code>/* @flow-runtime enable */</code>.</li>
</ul>
<p>You can override these plugin options on a per-file basis using <code>//@flow-runtime</code> comments, see the <Link to="/docs/pragmas">Pragmas</Link> documentation.</p>
<Example code={adderExample}
Expand Down

0 comments on commit 123aa74

Please sign in to comment.