react-native-flip
Version:
598 lines (531 loc) • 17 kB
JavaScript
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
"use strict";
function _toConsumableArray(arr) {
return (
_arrayWithoutHoles(arr) ||
_iterableToArray(arr) ||
_unsupportedIterableToArray(arr) ||
_nonIterableSpread()
);
}
function _nonIterableSpread() {
throw new TypeError(
"Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
return _arrayLikeToArray(o, minLen);
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter))
return Array.from(iter);
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly)
symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function(key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(
target,
key,
Object.getOwnPropertyDescriptor(source, key)
);
});
}
}
return target;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
const nullthrows = require("nullthrows");
const template = require("@babel/template").default;
/**
* Produces a Babel template that transforms an "import * as x from ..." or an
* "import x from ..." call into a "const x = importAll(...)" call with the
* corresponding id in it.
*/
const importTemplate = template.statement(`
var LOCAL = IMPORT(FILE);
`);
/**
* Produces a Babel template that transforms an "import {x as y} from ..." into
* "const y = require(...).x" call with the corresponding id in it.
*/
const importNamedTemplate = template.statement(`
var LOCAL = require(FILE).REMOTE;
`);
/**
* Produces a Babel template that transforms an "import ..." into
* "require(...)", which is considered a side-effect call.
*/
const importSideEffectTemplate = template.statement(`
require(FILE);
`);
/**
* Produces an "export all" template that traverses all exported symbols and
* re-exposes them.
*/
const exportAllTemplate = template.statements(`
var REQUIRED = require(FILE);
for (var KEY in REQUIRED) {
exports[KEY] = REQUIRED[KEY];
}
`);
/**
* Produces a "named export" or "default export" template to export a single
* symbol.
*/
const exportTemplate = template.statement(`
exports.REMOTE = LOCAL;
`);
/**
* Flags the exported module as a transpiled ES module. Needs to be kept in 1:1
* compatibility with Babel.
*/
const esModuleExportTemplate = template.statement(`
Object.defineProperty(exports, '__esModule', {value: true});
`);
/**
* Resolution template in case it is requested.
*/
const resolveTemplate = template.expression(`
require.resolve(NODE)
`);
/**
* Enforces the resolution of a path to a fully-qualified one, if set.
*/
function resolvePath(node, resolve) {
if (!resolve) {
return node;
}
return resolveTemplate({
NODE: node
});
} // eslint-disable-next-line no-redeclare
function withLocation(node, loc) {
if (Array.isArray(node)) {
return node.map(n => withLocation(n, loc));
}
if (!node.loc) {
return _objectSpread(
_objectSpread({}, node),
{},
{
loc
}
);
}
return node;
}
function importExportPlugin(_ref) {
let t = _ref.types;
const isDeclaration = t.isDeclaration,
isVariableDeclaration = t.isVariableDeclaration;
return {
visitor: {
ExportAllDeclaration(path, state) {
state.exportAll.push({
file: path.node.source.value,
loc: path.node.loc
});
path.remove();
},
ExportDefaultDeclaration(path, state) {
const declaration = path.node.declaration;
const id =
declaration.id || path.scope.generateUidIdentifier("default"); // $FlowFixMe Flow error uncovered by typing Babel more strictly
declaration.id = id;
const loc = path.node.loc;
state.exportDefault.push({
local: id.name,
loc
});
if (isDeclaration(declaration)) {
path.insertBefore(withLocation(declaration, loc));
} else {
path.insertBefore(
withLocation(
t.variableDeclaration("var", [
t.variableDeclarator(id, declaration)
]),
loc
)
);
}
path.remove();
},
ExportNamedDeclaration(path, state) {
if (path.node.exportKind && path.node.exportKind !== "value") {
return;
}
const declaration = path.node.declaration;
const loc = path.node.loc;
if (declaration) {
if (isVariableDeclaration(declaration)) {
declaration.declarations.forEach(d => {
switch (d.id.type) {
case "ObjectPattern":
{
const properties = d.id.properties;
properties.forEach(p => {
// $FlowFixMe Flow error uncovered by typing Babel more strictly
const name = p.key.name;
state.exportNamed.push({
local: name,
remote: name,
loc
});
});
}
break;
case "ArrayPattern":
{
const elements = d.id.elements;
elements.forEach(e => {
// $FlowFixMe Flow error uncovered by typing Babel more strictly
const name = e.name;
state.exportNamed.push({
local: name,
remote: name,
loc
});
});
}
break;
default:
{
// $FlowFixMe Flow error uncovered by typing Babel more strictly
const name = d.id.name;
state.exportNamed.push({
local: name,
remote: name,
loc
});
}
break;
}
});
} else {
const id = declaration.id || path.scope.generateUidIdentifier(); // $FlowFixMe Flow error uncovered by typing Babel more strictly
const name = id.name; // $FlowFixMe Flow error uncovered by typing Babel more strictly
declaration.id = id;
state.exportNamed.push({
local: name,
remote: name,
loc
});
}
path.insertBefore(declaration);
}
const specifiers = path.node.specifiers;
if (specifiers) {
specifiers.forEach(s => {
// $FlowFixMe Flow error uncovered by typing Babel more strictly
const local = s.local;
const remote = s.exported;
if (path.node.source) {
const temp = path.scope.generateUidIdentifier(local.name);
if (local.name === "default") {
path.insertBefore(
withLocation(
importTemplate({
IMPORT: state.importDefault,
FILE: resolvePath(
nullthrows(path.node.source),
state.opts.resolve
),
LOCAL: temp
}),
loc
)
);
state.exportNamed.push({
local: temp.name,
remote: remote.name,
loc
});
} else if (remote.name === "default") {
path.insertBefore(
withLocation(
importNamedTemplate({
FILE: resolvePath(
nullthrows(path.node.source),
state.opts.resolve
),
LOCAL: temp,
REMOTE: local
}),
loc
)
);
state.exportDefault.push({
local: temp.name,
loc
});
} else {
path.insertBefore(
withLocation(
importNamedTemplate({
FILE: resolvePath(
nullthrows(path.node.source),
state.opts.resolve
),
LOCAL: temp,
REMOTE: local
}),
loc
)
);
state.exportNamed.push({
local: temp.name,
remote: remote.name,
loc
});
}
} else {
if (remote.name === "default") {
state.exportDefault.push({
local: local.name,
loc
});
} else {
state.exportNamed.push({
local: local.name,
remote: remote.name,
loc
});
}
}
});
}
path.remove();
},
ImportDeclaration(path, state) {
if (path.node.importKind && path.node.importKind !== "value") {
return;
}
const file = path.node.source;
const specifiers = path.node.specifiers;
const loc = path.node.loc;
if (!specifiers.length) {
state.imports.push({
node: withLocation(
importSideEffectTemplate({
FILE: resolvePath(file, state.opts.resolve)
}),
loc
)
});
} else {
let sharedModuleImport = null;
if (
specifiers.filter(
s => s.type === "ImportSpecifier" && s.imported.name !== "default"
).length > 1
) {
sharedModuleImport = path.scope.generateUidIdentifierBasedOnNode(
file
);
path.scope.push({
id: sharedModuleImport,
init: withLocation(
t.callExpression(t.identifier("require"), [
resolvePath(file, state.opts.resolve)
]),
loc
)
});
}
specifiers.forEach(s => {
// $FlowFixMe Flow error uncovered by typing Babel more strictly
const imported = s.imported;
const local = s.local;
switch (s.type) {
case "ImportNamespaceSpecifier":
state.imports.push({
node: withLocation(
importTemplate({
IMPORT: state.importAll,
FILE: resolvePath(file, state.opts.resolve),
LOCAL: local
}),
loc
)
});
break;
case "ImportDefaultSpecifier":
state.imports.push({
node: withLocation(
importTemplate({
IMPORT: state.importDefault,
FILE: resolvePath(file, state.opts.resolve),
LOCAL: local
}),
loc
)
});
break;
case "ImportSpecifier":
if (imported.name === "default") {
state.imports.push({
node: withLocation(
importTemplate({
IMPORT: state.importDefault,
FILE: resolvePath(file, state.opts.resolve),
LOCAL: local
}),
loc
)
});
} else if (sharedModuleImport != null) {
path.scope.push({
id: local,
init: withLocation(
t.memberExpression(sharedModuleImport, imported),
loc
)
});
} else {
state.imports.push({
node: withLocation(
importNamedTemplate({
FILE: resolvePath(file, state.opts.resolve),
LOCAL: local,
REMOTE: imported
}),
loc
)
});
}
break;
default:
throw new TypeError("Unknown import type: " + s.type);
}
});
}
path.remove();
},
Program: {
enter(path, state) {
state.exportAll = [];
state.exportDefault = [];
state.exportNamed = [];
state.imports = [];
state.importAll = t.identifier(state.opts.importAll);
state.importDefault = t.identifier(state.opts.importDefault);
},
exit(path, state) {
const body = path.node.body; // state.imports = [node1, node2, node3, ...nodeN]
state.imports.reverse().forEach(e => {
// import nodes are added to the top of the program body
body.unshift(e.node);
});
state.exportDefault.forEach(e => {
body.push(
withLocation(
exportTemplate({
LOCAL: t.identifier(e.local),
REMOTE: t.identifier("default")
}),
e.loc
)
);
});
state.exportAll.forEach(e => {
body.push.apply(
body,
_toConsumableArray(
withLocation(
exportAllTemplate({
FILE: resolvePath(
t.stringLiteral(e.file),
state.opts.resolve
),
REQUIRED: path.scope.generateUidIdentifier(e.file),
KEY: path.scope.generateUidIdentifier("key")
}),
e.loc
)
)
);
});
state.exportNamed.forEach(e => {
body.push(
withLocation(
exportTemplate({
LOCAL: t.identifier(e.local),
REMOTE: t.identifier(e.remote)
}),
e.loc
)
);
});
if (
state.exportDefault.length ||
state.exportAll.length ||
state.exportNamed.length
) {
body.unshift(esModuleExportTemplate());
if (state.opts.out) {
state.opts.out.isESModule = true;
}
} else if (state.opts.out) {
state.opts.out.isESModule = false;
}
}
}
}
};
}
module.exports = importExportPlugin;