1 | import * as tslib_1 from "tslib";
|
2 |
|
3 | import * as crc32 from 'crc-32';
|
4 | import { existsSync } from 'fs';
|
5 | import { dirname, join, relative, resolve } from 'path';
|
6 | import { processComment } from './magic-comments';
|
7 | export var encipherImport = function (str) {
|
8 | return crc32.str(str).toString(32);
|
9 | };
|
10 |
|
11 | var syntax;
|
12 | try {
|
13 | syntax = require('babel-plugin-syntax-dynamic-import');
|
14 | }
|
15 | catch (err) {
|
16 | try {
|
17 | syntax = require('@babel/plugin-syntax-dynamic-import');
|
18 | }
|
19 | catch (e) {
|
20 | throw new Error('react-imported-component babel plugin is requiring `babel-plugin-syntax-dynamic-import` or `@babel/plugin-syntax-dynamic-import` to work. Please add this dependency.');
|
21 | }
|
22 | }
|
23 | syntax = syntax.default || syntax;
|
24 | var resolveImport = function (importName, file) {
|
25 | if (file === void 0) { file = ''; }
|
26 | if (importName.charAt(0) === '.') {
|
27 | return relative(process.cwd(), resolve(dirname(file), importName));
|
28 | }
|
29 | return importName;
|
30 | };
|
31 | var templateOptions = {
|
32 | placeholderPattern: /^([A-Z0-9]+)([A-Z0-9_]+)$/,
|
33 | };
|
34 | function getImportArg(callPath) {
|
35 | return callPath.get('arguments.0');
|
36 | }
|
37 | function getComments(callPath) {
|
38 | return callPath.has('leadingComments') ? callPath.get('leadingComments') : [];
|
39 | }
|
40 |
|
41 | var configurationFile = join(process.cwd(), '.imported.js');
|
42 | var defaultConfiguration = (existsSync(configurationFile)
|
43 | ? require(configurationFile)
|
44 | : {});
|
45 | export var createTransformer = function (_a, excludeMacro, configuration) {
|
46 | var t = _a.types, template = _a.template;
|
47 | if (excludeMacro === void 0) { excludeMacro = false; }
|
48 | if (configuration === void 0) { configuration = defaultConfiguration; }
|
49 | var headerTemplate = template("var importedWrapper = require('react-imported-component/wrapper');", templateOptions);
|
50 | var importRegistration = template('importedWrapper(MARK, IMPORT)', templateOptions);
|
51 | var hasImports = new Set();
|
52 | var visitedNodes = new Map();
|
53 | return {
|
54 | traverse: function (programPath, fileName) {
|
55 | var isBootstrapFile = false;
|
56 | programPath.traverse({
|
57 | ImportDeclaration: function (path) {
|
58 | if (excludeMacro) {
|
59 | return;
|
60 | }
|
61 | var source = path.node.source.value;
|
62 | if (source === 'react-imported-component/macro') {
|
63 | var specifiers = path.node.specifiers;
|
64 | path.remove();
|
65 | var assignName = 'assignImportedComponents';
|
66 | if (specifiers.length === 1 && specifiers[0].imported.name === assignName) {
|
67 | isBootstrapFile = true;
|
68 | programPath.node.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier(assignName), t.identifier(assignName))], t.stringLiteral('react-imported-component/boot')));
|
69 | }
|
70 | else {
|
71 | programPath.node.body.unshift(t.importDeclaration(specifiers.map(function (spec) {
|
72 | return t.importSpecifier(t.identifier(spec.imported.name), t.identifier(spec.imported.name));
|
73 | }), t.stringLiteral('react-imported-component')));
|
74 | }
|
75 | }
|
76 | },
|
77 | Import: function (_a) {
|
78 | var parentPath = _a.parentPath;
|
79 | if (visitedNodes.has(parentPath.node)) {
|
80 | return;
|
81 | }
|
82 | var newImport = parentPath.node;
|
83 | var rawImport = getImportArg(parentPath);
|
84 | var importName = rawImport.node.value;
|
85 | var rawComments = getComments(rawImport);
|
86 | var comments = rawComments.map(function (parent) { return parent.node.value; });
|
87 | var newComments = processComment(configuration, comments, importName, fileName, {
|
88 | isBootstrapFile: isBootstrapFile,
|
89 | });
|
90 | if (newComments !== comments) {
|
91 | rawComments.forEach(function (comment) { return comment.remove(); });
|
92 | newComments.forEach(function (comment) {
|
93 | rawImport.addComment('leading', " " + comment + " ");
|
94 | });
|
95 | }
|
96 | if (!importName) {
|
97 | return;
|
98 | }
|
99 | var requiredFileHash = encipherImport(resolveImport(importName, fileName));
|
100 | var replace = null;
|
101 | replace = importRegistration({
|
102 | MARK: t.stringLiteral("imported_" + requiredFileHash + "_component"),
|
103 | IMPORT: newImport,
|
104 | });
|
105 | hasImports.add(fileName);
|
106 | visitedNodes.set(newImport, true);
|
107 | parentPath.replaceWith(replace);
|
108 | },
|
109 | });
|
110 | },
|
111 | finish: function (node, filename) {
|
112 | if (!hasImports.has(filename)) {
|
113 | return;
|
114 | }
|
115 | node.body.unshift(headerTemplate());
|
116 | },
|
117 | hasImports: hasImports,
|
118 | };
|
119 | };
|
120 | export var babelPlugin = function (babel, options) {
|
121 | if (options === void 0) { options = {}; }
|
122 | var transformer = createTransformer(babel, false, tslib_1.__assign({}, defaultConfiguration, options));
|
123 | return {
|
124 | inherits: syntax,
|
125 | visitor: {
|
126 | Program: {
|
127 | enter: function (programPath, _a) {
|
128 | var file = _a.file;
|
129 | transformer.traverse(programPath, file.opts.filename);
|
130 | },
|
131 | exit: function (_a, _b) {
|
132 | var node = _a.node;
|
133 | var file = _b.file;
|
134 | transformer.finish(node, file.opts.filename);
|
135 | },
|
136 | },
|
137 | },
|
138 | };
|
139 | };
|