mirror of https://github.com/status-im/metro.git
Remove old extract-dependencies logic
Reviewed By: davidaurelio Differential Revision: D6447749 fbshipit-source-id: 39c4960da65a9d8ab1e2615d48f5c2868a17f82b
This commit is contained in:
parent
03e735d232
commit
b456f7b61a
|
@ -25,18 +25,18 @@ jest
|
|||
platform: () => 'test',
|
||||
}));
|
||||
|
||||
// This doesn't have state, and it's huge (Babel) so it's much faster to
|
||||
// require it only once. The variable name is prefixed with "mock" as an escape-hatch
|
||||
// for babel-plugin-jest-hoist.
|
||||
let mockExtractDependencies;
|
||||
jest.mock('../../JSTransformer/worker/extract-dependencies', () => {
|
||||
if (!mockExtractDependencies) {
|
||||
mockExtractDependencies = require.requireActual(
|
||||
'../../JSTransformer/worker/extract-dependencies',
|
||||
);
|
||||
// Super-simple mock for extracting dependencies
|
||||
const extractDependencies = function(sourceCode: string) {
|
||||
const regexp = /require\s*\(\s*(['"])(.*?)\1\s*\)/g;
|
||||
const deps = [];
|
||||
let match;
|
||||
|
||||
while ((match = regexp.exec(sourceCode))) {
|
||||
deps.push(match[2]);
|
||||
}
|
||||
return mockExtractDependencies;
|
||||
});
|
||||
|
||||
return deps;
|
||||
};
|
||||
|
||||
jest.mock('graceful-fs', () => require('fs'));
|
||||
|
||||
|
@ -110,14 +110,9 @@ describe('traverseDependencies', function() {
|
|||
transformCache: require('TransformCaching').mocked(),
|
||||
transformCode: (module, sourceCode, transformOptions) => {
|
||||
return new Promise(resolve => {
|
||||
let deps = {dependencies: [], dependencyOffsets: []};
|
||||
const deps = {dependencies: []};
|
||||
if (!module.path.endsWith('.json')) {
|
||||
if (!mockExtractDependencies) {
|
||||
mockExtractDependencies = require.requireActual(
|
||||
'../../JSTransformer/worker/extract-dependencies',
|
||||
);
|
||||
}
|
||||
deps = mockExtractDependencies(sourceCode);
|
||||
deps.dependencies = extractDependencies(sourceCode);
|
||||
}
|
||||
resolve({...deps, code: sourceCode});
|
||||
});
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+javascript_foundation
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const extractDependencies = require('../extract-dependencies');
|
||||
|
||||
describe('Dependency extraction:', () => {
|
||||
it('can extract calls to require', () => {
|
||||
const code = `require('foo/bar');
|
||||
var React = require("React");
|
||||
var A = React.createClass({
|
||||
render: function() {
|
||||
return require ( "Component" );
|
||||
}
|
||||
});
|
||||
require
|
||||
('more');`;
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['foo/bar', 'React', 'Component', 'more']);
|
||||
expect(dependencyOffsets).toEqual([8, 46, 147, 203]);
|
||||
});
|
||||
|
||||
it('can extract calls to require.async', () => {
|
||||
const code = `foo();
|
||||
require.async('bar').then(() => {});`;
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['bar']);
|
||||
expect(dependencyOffsets).toEqual([27]);
|
||||
});
|
||||
|
||||
it('does not extract require method calls', () => {
|
||||
const code = `
|
||||
require('a');
|
||||
foo.require('b');
|
||||
bar.
|
||||
require ( 'c').require('d');require('e')`;
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['a', 'e']);
|
||||
expect(dependencyOffsets).toEqual([15, 98]);
|
||||
});
|
||||
|
||||
it('does not extract require calls from strings', () => {
|
||||
const code = `require('foo');
|
||||
var React = '\\'require("React")';
|
||||
var a = ' // require("yadda")';
|
||||
var a = ' /* require("yadda") */';
|
||||
var A = React.createClass({
|
||||
render: function() {
|
||||
return require ( "Component" );
|
||||
}
|
||||
});
|
||||
" \\" require('more')";`;
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['foo', 'Component']);
|
||||
expect(dependencyOffsets).toEqual([8, 226]);
|
||||
});
|
||||
|
||||
it('does not extract require calls in comments', () => {
|
||||
const code = `require('foo')//require("not/this")
|
||||
/* A comment here with a require('call') that should not be extracted */require('bar')
|
||||
// ending comment without newline require("baz")`;
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['foo', 'bar']);
|
||||
expect(dependencyOffsets).toEqual([8, 122]);
|
||||
});
|
||||
|
||||
it('deduplicates dependencies', () => {
|
||||
const code = `require('foo');require( "foo" );
|
||||
require("foo");`;
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['foo']);
|
||||
expect(dependencyOffsets).toEqual([8, 24, 47]);
|
||||
});
|
||||
|
||||
it('does not extract calls to function with names that start with "require"', () => {
|
||||
const code = "arbitraryrequire('foo');";
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual([]);
|
||||
expect(dependencyOffsets).toEqual([]);
|
||||
});
|
||||
|
||||
it('throws on calls to require with non-static arguments', () => {
|
||||
const code = "require('foo/' + bar)";
|
||||
|
||||
expect(() => extractDependencies(code)).toThrowError(
|
||||
'require() must have a single string literal argument',
|
||||
);
|
||||
});
|
||||
|
||||
it('throws on calls to require with non-static arguments, nested deeper than one level inside of a try block', () => {
|
||||
const code = "try { if (1) { require('foo/' + bar) } } catch (e) { }";
|
||||
|
||||
expect(() => extractDependencies(code)).toThrowError(
|
||||
'require() must have a single string literal argument',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not throw on calls to require with non-static arguments, nested directly inside of a try block', () => {
|
||||
const code = "try { require('foo/' + bar) } catch (e) { }";
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual([]);
|
||||
expect(dependencyOffsets).toEqual([]);
|
||||
});
|
||||
|
||||
it('does not get confused by previous states', () => {
|
||||
// yes, this was a bug
|
||||
const code = 'require("a");/* a comment */ var a = /[a]/.test(\'a\');';
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['a']);
|
||||
expect(dependencyOffsets).toEqual([8]);
|
||||
});
|
||||
|
||||
it('can handle regular expressions', () => {
|
||||
const code = "require('a'); /[\"']/.test('foo'); require(\"b\");";
|
||||
|
||||
const {dependencies, dependencyOffsets} = extractDependencies(code);
|
||||
expect(dependencies).toEqual(['a', 'b']);
|
||||
expect(dependencyOffsets).toEqual([8, 42]);
|
||||
});
|
||||
});
|
|
@ -1,80 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const babel = require('babel-core');
|
||||
const babylon = require('babylon');
|
||||
|
||||
/**
|
||||
* Extracts dependencies (module IDs imported with the `require` function) from
|
||||
* a string containing code. This walks the full AST for correctness (versus
|
||||
* using, for example, regular expressions, that would be faster but inexact.)
|
||||
*
|
||||
* The result of the dependency extraction is an de-duplicated array of
|
||||
* dependencies, and an array of offsets to the string literals with module IDs.
|
||||
* The index points to the opening quote.
|
||||
*
|
||||
* Note the technique of recognizing the identifier "require" is not proper
|
||||
* because it ignores that the scope may have reassigned or shadowed that value,
|
||||
* but it's a tradeoff for simplicity.
|
||||
*/
|
||||
|
||||
function extractDependencies(code: string, filename: string) {
|
||||
const ast = babylon.parse(code, {sourceType: 'module'});
|
||||
const dependencies = new Set();
|
||||
const dependencyOffsets = [];
|
||||
|
||||
function pushDependency(nodeArgs, parentType) {
|
||||
const arg = nodeArgs[0];
|
||||
if (nodeArgs.length != 1 || arg.type !== 'StringLiteral') {
|
||||
// Dynamic requires directly inside of a try statement are considered optional dependencies
|
||||
if (parentType === 'TryStatement') {
|
||||
return;
|
||||
}
|
||||
throw new Error(
|
||||
`require() must have a single string literal argument: ${filename}:${arg
|
||||
.loc.start.line - 1}`,
|
||||
);
|
||||
}
|
||||
dependencyOffsets.push(arg.start);
|
||||
dependencies.add(arg.value);
|
||||
}
|
||||
|
||||
babel.traverse(ast, {
|
||||
CallExpression(path) {
|
||||
const node = path.node;
|
||||
const callee = node.callee;
|
||||
const parent = path.scope.parentBlock;
|
||||
if (callee.type === 'Identifier' && callee.name === 'require') {
|
||||
pushDependency(node.arguments, parent.type);
|
||||
}
|
||||
if (callee.type !== 'MemberExpression') {
|
||||
return;
|
||||
}
|
||||
const obj = callee.object;
|
||||
const prop = callee.property;
|
||||
if (
|
||||
obj.type === 'Identifier' &&
|
||||
obj.name === 'require' &&
|
||||
!callee.computed &&
|
||||
prop.name === 'async'
|
||||
) {
|
||||
pushDependency(node.arguments);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return {dependencyOffsets, dependencies: Array.from(dependencies)};
|
||||
}
|
||||
|
||||
module.exports = extractDependencies;
|
Loading…
Reference in New Issue