UNPKG

35.3 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const babel_traverse_1 = require("babel-traverse");
4const babel_generator_1 = require("babel-generator");
5const html_1 = require("html");
6const babel_core_1 = require("babel-core");
7const ts = require("typescript");
8const class_1 = require("./class");
9const utils_1 = require("./utils");
10const t = require("babel-types");
11const constant_1 = require("./constant");
12const adapter_1 = require("./adapter");
13const options_1 = require("./options");
14const lodash_1 = require("lodash");
15const env_1 = require("./env");
16const template = require('babel-template');
17function getIdsFromMemberProps(member) {
18 let ids = [];
19 const { object, property } = member;
20 if (t.isMemberExpression(object)) {
21 ids = ids.concat(getIdsFromMemberProps(object));
22 }
23 if (t.isThisExpression(object)) {
24 ids.push('this');
25 }
26 if (t.isIdentifier(object)) {
27 ids.push(object.name);
28 }
29 if (t.isIdentifier(property)) {
30 ids.push(property.name);
31 }
32 return ids;
33}
34/**
35 * TS 编译器会把 class property 移到构造器,
36 * 而小程序要求 `config` 和所有函数在初始化(after new Class)之后就收集到所有的函数和 config 信息,
37 * 所以当如构造器里有 this.func = () => {...} 的形式,就给他转换成普通的 classProperty function
38 * 如果有 config 就给他还原
39 */
40function resetTSClassProperty(body) {
41 for (const method of body) {
42 if (t.isClassMethod(method) && method.kind === 'constructor') {
43 if (t.isBlockStatement(method.body)) {
44 method.body.body = method.body.body.filter(statement => {
45 if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression)) {
46 const expr = statement.expression;
47 const { left, right } = expr;
48 if (t.isMemberExpression(left) &&
49 t.isThisExpression(left.object) &&
50 t.isIdentifier(left.property)) {
51 if ((t.isArrowFunctionExpression(right) || t.isFunctionExpression(right))
52 ||
53 (left.property.name === 'config' && t.isObjectExpression(right))) {
54 const classProp = t.classProperty(left.property, right);
55 body.push(classProp);
56 handleThirdPartyComponent(classProp);
57 return false;
58 }
59 }
60 }
61 return true;
62 });
63 }
64 }
65 }
66}
67function handleClosureJSXFunc(jsx, mainClass) {
68 // 在 ./functional.ts 会把 FunctionExpression 转化为 arrowFunctionExpr
69 // 所以我们这里只处理一种情况
70 const arrowFunc = jsx.findParent(p => p.isArrowFunctionExpression());
71 if (arrowFunc && arrowFunc.isArrowFunctionExpression()) {
72 const parentPath = arrowFunc.parentPath;
73 if (parentPath.isVariableDeclarator()) {
74 const id = parentPath.node.id;
75 if (t.isIdentifier(id) && /^render[A-Z]/.test(id.name)) {
76 const funcName = `renderClosure${id.name.slice(6, id.name.length)}`;
77 mainClass.node.body.body.push(t.classProperty(t.identifier(funcName), lodash_1.cloneDeep(arrowFunc.node)));
78 parentPath.scope.rename(id.name, funcName);
79 arrowFunc.replaceWith(t.memberExpression(t.thisExpression(), t.identifier(funcName)));
80 }
81 }
82 }
83}
84function findDeclarationScope(path, id) {
85 const scopePath = path.findParent(p => !!p.scope.getOwnBindingIdentifier(id.name));
86 if (scopePath) {
87 return scopePath;
88 }
89 throw utils_1.codeFrameError(path.node, '该引用从未被定义');
90}
91function buildFullPathThisPropsRef(id, memberIds, path) {
92 const scopePath = findDeclarationScope(path, id);
93 const binding = scopePath.scope.getOwnBinding(id.name);
94 if (binding) {
95 const bindingPath = binding.path;
96 if (bindingPath.isVariableDeclarator()) {
97 const dclId = bindingPath.get('id');
98 const dclInit = bindingPath.get('init');
99 let dclInitIds = [];
100 if (dclInit.isMemberExpression()) {
101 dclInitIds = getIdsFromMemberProps(dclInit.node);
102 if (dclId.isIdentifier()) {
103 memberIds.shift();
104 }
105 if (dclInitIds[0] === 'this' && dclInitIds[1] === 'props') {
106 return template(dclInitIds.concat(memberIds).join('.'))().expression;
107 }
108 }
109 }
110 }
111}
112function handleThirdPartyComponent(expr) {
113 if (t.isClassProperty(expr) && expr.key.name === 'config' && t.isObjectExpression(expr.value)) {
114 const properties = expr.value.properties;
115 findThirdPartyComponent(properties);
116 }
117}
118function findThirdPartyComponent(properties) {
119 for (const prop of properties) {
120 if (t.isObjectProperty(prop) &&
121 (t.isIdentifier(prop.key, { name: 'usingComponents' }) || t.isStringLiteral(prop.key, { value: 'usingComponents' })) &&
122 t.isObjectExpression(prop.value)) {
123 for (const value of prop.value.properties) {
124 if (t.isObjectProperty(value)) {
125 if (t.isStringLiteral(value.key)) {
126 constant_1.THIRD_PARTY_COMPONENTS.add(value.key.value);
127 }
128 if (t.isIdentifier(value.key)) {
129 constant_1.THIRD_PARTY_COMPONENTS.add(value.key.name);
130 }
131 }
132 }
133 }
134 }
135}
136function transform(options) {
137 if (options.adapter) {
138 adapter_1.setAdapter(options.adapter);
139 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
140 constant_1.DEFAULT_Component_SET.clear();
141 constant_1.DEFAULT_Component_SET.add('div');
142 constant_1.DEFAULT_Component_SET.add('Text');
143 constant_1.setFnPrefix('prv-fn-');
144 }
145 }
146 if (adapter_1.Adapter.type === "swan" /* swan */ || adapter_1.Adapter.type === "quickapp" /* quickapp */) {
147 constant_1.setLoopOriginal('privateOriginal');
148 constant_1.setLoopCallee('anonymousCallee_');
149 constant_1.setLoopState('loopState');
150 }
151 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
152 constant_1.setIsTaroReady('priTaroCompReady');
153 constant_1.setCompId('priCompid');
154 }
155 constant_1.THIRD_PARTY_COMPONENTS.clear();
156 const code = options.isTyped
157 ? ts.transpile(options.code, {
158 jsx: options.sourcePath.endsWith('.tsx') ? ts.JsxEmit.Preserve : ts.JsxEmit.None,
159 target: ts.ScriptTarget.ESNext,
160 importHelpers: true,
161 noEmitHelpers: true
162 })
163 : options.code;
164 options.env = Object.assign({ 'process.env.TARO_ENV': options.adapter || 'weapp' }, options.env || {});
165 options_1.setTransformOptions(options);
166 utils_1.setting.sourceCode = code;
167 let hasReduxBinding = false;
168 // babel-traverse 无法生成 Hub
169 // 导致 Path#getSource|buildCodeFrameError 都无法直接使用
170 // 原因大概是 babylon.parse 没有生成 File 实例导致 scope 和 path 原型上都没有 `file`
171 // 将来升级到 babel@7 可以直接用 parse 而不是 transform
172 const ast = babel_core_1.transform(code, options_1.buildBabelTransformOptions()).ast;
173 if (options.isNormal) {
174 if (options.isTyped) {
175 const mainClassNode = ast.program.body.find(v => {
176 return t.isClassDeclaration(v);
177 });
178 if (mainClassNode) {
179 resetTSClassProperty(mainClassNode.body.body);
180 }
181 }
182 return { ast };
183 }
184 // transformFromAst(ast, code)
185 let result;
186 const componentSourceMap = new Map();
187 const imageSource = new Set();
188 const importSources = new Set();
189 const classMethods = new Map();
190 let componentProperies = [];
191 let mainClass;
192 let storeName;
193 let renderMethod;
194 let isImportTaro = false;
195 babel_traverse_1.default(ast, {
196 Program: {
197 exit(path) {
198 for (const stem of path.node.body) {
199 if (t.isImportDeclaration(stem)) {
200 if (stem.source.value === constant_1.TARO_PACKAGE_NAME) {
201 const specs = stem.specifiers;
202 if (specs.some(s => t.isImportDefaultSpecifier(s) && s.local.name === 'Taro')) {
203 continue;
204 }
205 specs.unshift(t.importDefaultSpecifier(t.identifier('Taro')));
206 }
207 }
208 }
209 }
210 },
211 MemberExpression(path) {
212 const { property } = path.node;
213 const right = path.getSibling('right');
214 if (t.isIdentifier(property, { name: 'config' }) && path.parentPath.isAssignmentExpression() && right.isObjectExpression()) {
215 const properties = right.node.properties;
216 findThirdPartyComponent(properties);
217 }
218 },
219 JSXText(path) {
220 if (adapter_1.Adapter.type !== "quickapp" /* quickapp */) {
221 return;
222 }
223 const value = path.node.value;
224 if (!value.trim()) {
225 return;
226 }
227 utils_1.replaceJSXTextWithTextComponent(path);
228 },
229 TemplateLiteral(path) {
230 const nodes = [];
231 const { quasis, expressions } = path.node;
232 let index = 0;
233 if (path.parentPath.isTaggedTemplateExpression()) {
234 return;
235 }
236 for (const elem of quasis) {
237 if (elem.value.cooked) {
238 nodes.push(t.stringLiteral(elem.value.cooked));
239 }
240 if (index < expressions.length) {
241 const expr = expressions[index++];
242 if (!t.isStringLiteral(expr, { value: '' })) {
243 nodes.push(expr);
244 }
245 }
246 }
247 // + 号连接符必须保证第一和第二个 node 都是字符串
248 if (!t.isStringLiteral(nodes[0]) && !t.isStringLiteral(nodes[1])) {
249 nodes.unshift(t.stringLiteral(''));
250 }
251 let root = nodes[0];
252 for (let i = 1; i < nodes.length; i++) {
253 root = t.binaryExpression('+', root, nodes[i]);
254 }
255 path.replaceWith(root);
256 },
257 ClassDeclaration(path) {
258 mainClass = path;
259 const superClass = utils_1.getSuperClassCode(path);
260 if (superClass) {
261 try {
262 componentProperies = transform({
263 isRoot: false,
264 isApp: false,
265 code: superClass.code,
266 isTyped: true,
267 sourcePath: superClass.sourcePath,
268 outputPath: superClass.sourcePath,
269 sourceDir: options.sourceDir
270 }).componentProperies;
271 }
272 catch (error) {
273 //
274 }
275 }
276 },
277 ClassExpression(path) {
278 mainClass = path;
279 },
280 ClassMethod(path) {
281 if (t.isIdentifier(path.node.key)) {
282 if (path.node.key.name === 'render') {
283 renderMethod = path;
284 }
285 classMethods.set(path.node.key.name, path);
286 }
287 },
288 IfStatement(path) {
289 const consequent = path.get('consequent');
290 if (!consequent.isBlockStatement()) {
291 consequent.replaceWith(t.blockStatement([
292 consequent.node
293 ]));
294 }
295 },
296 CallExpression(path) {
297 const callee = path.get('callee');
298 if (utils_1.isContainJSXElement(path)) {
299 return;
300 }
301 if (callee.isReferencedMemberExpression()) {
302 const id = utils_1.findFirstIdentifierFromMemberExpression(callee.node);
303 const property = callee.node.property;
304 if (t.isIdentifier(property) && property.name.startsWith('on')) {
305 const funcExpr = path.findParent(p => p.isFunctionExpression());
306 if (funcExpr && funcExpr.isFunctionExpression()) {
307 const taroAPI = funcExpr.findParent(p => p.isCallExpression() && t.isMemberExpression(p.node.callee) && t.isIdentifier(p.node.callee.object, { name: 'Taro' }));
308 if (taroAPI && taroAPI.isCallExpression()) {
309 throw utils_1.codeFrameError(funcExpr.node, '在回调函数使用从 props 传递的函数时,请把回调函数改造为箭头函数并一直使用 `this` 取值');
310 }
311 }
312 }
313 const calleeIds = getIdsFromMemberProps(callee.node);
314 if (t.isIdentifier(id) && id.name.startsWith('on') && "alipay" /* alipay */ !== adapter_1.Adapter.type) {
315 const fullPath = buildFullPathThisPropsRef(id, calleeIds, path);
316 if (fullPath) {
317 path.replaceWith(t.callExpression(fullPath, path.node.arguments));
318 }
319 }
320 }
321 if (callee.isReferencedIdentifier()) {
322 const id = callee.node;
323 const ids = [id.name];
324 if (t.isIdentifier(id) && id.name.startsWith('on')) {
325 const funcExpr = path.findParent(p => p.isFunctionExpression());
326 if (funcExpr && funcExpr.isFunctionExpression()) {
327 const taroAPI = funcExpr.findParent(p => p.isCallExpression() && t.isMemberExpression(p.node.callee) && t.isIdentifier(p.node.callee.object, { name: 'Taro' }));
328 if (taroAPI && taroAPI.isCallExpression()) {
329 throw utils_1.codeFrameError(funcExpr.node, '在回调函数使用从 props 传递的函数时,请把回调函数改造为箭头函数并一直使用 `this` 取值');
330 }
331 }
332 const fullPath = buildFullPathThisPropsRef(id, ids, path);
333 if (fullPath) {
334 path.replaceWith(t.callExpression(fullPath, path.node.arguments));
335 }
336 }
337 }
338 },
339 // JSXIdentifier (path) {
340 // const parentPath = path.parentPath
341 // if (!parentPath.isJSXAttribute()) {
342 // return
343 // }
344 // const element = parentPath.parentPath
345 // if (!element.isJSXOpeningElement()) {
346 // return
347 // }
348 // const elementName = element.get('name')
349 // if (!elementName.isJSXIdentifier()) {
350 // return
351 // }
352 // if (DEFAULT_Component_SET.has(elementName.node.name)) {
353 // return
354 // }
355 // const expr = parentPath.get('value.expression')
356 // },
357 JSXMemberExpression(path) {
358 const { property, object } = path.node;
359 if (!t.isJSXIdentifier(property, { name: 'Provider' })) {
360 throw utils_1.codeFrameError(property, '只能在使用 Context.Provider 的情况下才能使用 JSX 成员表达式');
361 }
362 if (!t.isJSXIdentifier(object)) {
363 return;
364 }
365 const jsx = path.parentPath.parentPath;
366 if (jsx.isJSXElement()) {
367 const componentName = `${object.name}${constant_1.CONTEXT_PROVIDER}`;
368 jsx.node.openingElement.name = t.jSXIdentifier(componentName);
369 if (jsx.node.closingElement) {
370 jsx.node.closingElement.name = t.jSXIdentifier(componentName);
371 }
372 }
373 },
374 JSXElement(path) {
375 const assignment = path.findParent(p => p.isAssignmentExpression());
376 if (assignment && assignment.isAssignmentExpression() && !options.isTyped) {
377 const left = assignment.node.left;
378 if (t.isIdentifier(left)) {
379 const binding = assignment.scope.getBinding(left.name);
380 if (binding && binding.scope === assignment.scope) {
381 if (binding.path.isVariableDeclarator()) {
382 binding.path.node.init = path.node;
383 assignment.remove();
384 }
385 else {
386 throw utils_1.codeFrameError(path.node, '同一个作用域的JSX 变量延时赋值没有意义。详见:https://github.com/NervJS/taro/issues/550');
387 }
388 }
389 }
390 }
391 const switchStatement = path.findParent(p => p.isSwitchStatement());
392 if (switchStatement && switchStatement.isSwitchStatement()) {
393 const { discriminant, cases } = switchStatement.node;
394 const ifStatement = cases.map((Case, index) => {
395 const [consequent] = Case.consequent;
396 if (!t.isBlockStatement(consequent)) {
397 throw utils_1.codeFrameError(switchStatement.node, '含有 JSX 的 switch case 语句必须每种情况都用花括号 `{}` 包裹结果');
398 }
399 const block = t.blockStatement(consequent.body.filter(b => !t.isBreakStatement(b)));
400 if (index !== cases.length - 1 && t.isNullLiteral(Case.test)) {
401 throw utils_1.codeFrameError(Case, '含有 JSX 的 switch case 语句只有最后一个 case 才能是 default');
402 }
403 // tslint:disable-next-line: strict-type-predicates
404 const test = Case.test === null ? t.nullLiteral() : t.binaryExpression('===', discriminant, Case.test);
405 return { block, test };
406 }).reduceRight((ifStatement, item) => {
407 if (t.isNullLiteral(item.test)) {
408 ifStatement.alternate = item.block;
409 return ifStatement;
410 }
411 const newStatement = t.ifStatement(item.test, item.block, t.isBooleanLiteral(ifStatement.test, { value: false })
412 ? ifStatement.alternate
413 : ifStatement);
414 return newStatement;
415 }, t.ifStatement(t.booleanLiteral(false), t.blockStatement([])));
416 switchStatement.insertAfter(ifStatement);
417 switchStatement.remove();
418 }
419 const isForStatement = (p) => p && (p.isForStatement() || p.isForInStatement() || p.isForOfStatement());
420 const forStatement = path.findParent(isForStatement);
421 if (isForStatement(forStatement)) {
422 throw utils_1.codeFrameError(forStatement.node, '不能使用 for 循环操作 JSX 元素,详情:https://github.com/NervJS/taro/blob/master/packages/eslint-plugin-taro/docs/manipulate-jsx-as-array.md');
423 }
424 const loopCallExpr = path.findParent(p => utils_1.isArrayMapCallExpression(p));
425 if (loopCallExpr && loopCallExpr.isCallExpression()) {
426 const [func] = loopCallExpr.node.arguments;
427 if (t.isArrowFunctionExpression(func) && !t.isBlockStatement(func.body)) {
428 func.body = t.blockStatement([
429 t.returnStatement(func.body)
430 ]);
431 }
432 }
433 handleClosureJSXFunc(path, mainClass);
434 },
435 JSXOpeningElement(path) {
436 const { name } = path.node.name;
437 const binding = path.scope.getBinding(name);
438 if (process.env.NODE_ENV !== 'test' && binding && binding.kind === 'module') {
439 const bindingPath = binding.path;
440 if (bindingPath.parentPath.isImportDeclaration()) {
441 const source = bindingPath.parentPath.node.source;
442 if (constant_1.DEFAULT_Component_SET.has(name) && source.value !== constant_1.COMPONENTS_PACKAGE_NAME) {
443 throw utils_1.codeFrameError(bindingPath.parentPath.node, `内置组件名: '${name}' 只能从 ${constant_1.COMPONENTS_PACKAGE_NAME} 引入。`);
444 }
445 if (name === 'Fragment') {
446 path.node.name = t.jSXIdentifier('block');
447 }
448 }
449 }
450 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
451 if (name === 'View') {
452 path.node.name = t.jSXIdentifier('div');
453 }
454 if (name === 'Block') {
455 path.node.name = t.jSXIdentifier('block');
456 }
457 }
458 if (name === 'Provider') {
459 const modules = path.scope.getAllBindings('module');
460 const providerBinding = Object.values(modules).some((m) => m.identifier.name === 'Provider');
461 if (providerBinding) {
462 path.node.name = t.jSXIdentifier('View');
463 const store = path.node.attributes.find(attr => attr.name.name === 'store');
464 if (store && t.isJSXExpressionContainer(store.value) && t.isIdentifier(store.value.expression)) {
465 storeName = store.value.expression.name;
466 }
467 path.node.attributes = [];
468 }
469 }
470 if (constant_1.IMAGE_COMPONENTS.has(name)) {
471 for (const attr of path.node.attributes) {
472 if (attr.name.name === 'src') {
473 if (t.isStringLiteral(attr.value)) {
474 imageSource.add(attr.value.value);
475 }
476 else if (t.isJSXExpressionContainer(attr.value)) {
477 if (t.isStringLiteral(attr.value.expression)) {
478 imageSource.add(attr.value.expression.value);
479 }
480 }
481 }
482 }
483 }
484 },
485 JSXAttribute(path) {
486 const { name, value } = path.node;
487 if (options.jsxAttributeNameReplace) {
488 for (const r in options.jsxAttributeNameReplace) {
489 if (options.jsxAttributeNameReplace.hasOwnProperty(r)) {
490 const element = options.jsxAttributeNameReplace[r];
491 if (t.isJSXIdentifier(name, { name: r })) {
492 path.node.name = t.jSXIdentifier(element);
493 }
494 }
495 }
496 }
497 // tslint:disable-next-line: strict-type-predicates
498 if (!t.isJSXIdentifier(name) || value === null || t.isStringLiteral(value) || t.isJSXElement(value)) {
499 return;
500 }
501 const expr = value.expression;
502 const exprPath = path.get('value.expression');
503 const classDecl = path.findParent(p => p.isClassDeclaration());
504 const classDeclName = classDecl && classDecl.isClassDeclaration() && lodash_1.get(classDecl, 'node.id.name', '');
505 let isConverted = false;
506 if (classDeclName) {
507 isConverted = classDeclName === '_C' || classDeclName.endsWith('Tmpl');
508 }
509 if (!t.isBinaryExpression(expr, { operator: '+' }) && !t.isLiteral(expr) && name.name === 'style' && !isConverted) {
510 const jsxID = path.findParent(p => p.isJSXOpeningElement()).get('name');
511 if (jsxID && jsxID.isJSXIdentifier() && constant_1.DEFAULT_Component_SET.has(jsxID.node.name)) {
512 exprPath.replaceWith(t.callExpression(t.identifier(constant_1.INTERNAL_INLINE_STYLE), [expr]));
513 }
514 }
515 if (name.name.startsWith('on')) {
516 if (exprPath.isReferencedIdentifier()) {
517 const ids = [expr.name];
518 const fullPath = buildFullPathThisPropsRef(expr, ids, path);
519 if (fullPath) {
520 exprPath.replaceWith(fullPath);
521 }
522 }
523 if (exprPath.isReferencedMemberExpression()) {
524 const id = utils_1.findFirstIdentifierFromMemberExpression(expr);
525 const ids = getIdsFromMemberProps(expr);
526 if (t.isIdentifier(id)) {
527 const fullPath = buildFullPathThisPropsRef(id, ids, path);
528 if (fullPath) {
529 exprPath.replaceWith(fullPath);
530 }
531 }
532 }
533 // @TODO: bind 的处理待定
534 }
535 },
536 ClassProperty(path) {
537 const { key: { name }, value } = path.node;
538 if (t.isArrowFunctionExpression(value) || t.isFunctionExpression(value)) {
539 classMethods.set(name, path);
540 if (name.startsWith('render')) {
541 path.replaceWith(t.classMethod('method', t.identifier(name), value.params, t.isBlockStatement(value.body) ? value.body : t.blockStatement([
542 t.returnStatement(value.body)
543 ])));
544 }
545 }
546 if (adapter_1.Adapter.type !== "quickapp" /* quickapp */) {
547 return;
548 }
549 if (path.node.key.name === 'defaultProps' && t.isObjectExpression(path.node.value)) {
550 const props = path.node.value.properties;
551 for (const prop of props) {
552 if (t.isObjectProperty(prop)) {
553 if (t.isStringLiteral(prop.key) && /[A-Z]/.test(prop.key.value) && !prop.key.value.startsWith('on')) {
554 prop.key = t.stringLiteral(lodash_1.snakeCase(prop.key.value));
555 }
556 if (t.isIdentifier(prop.key) && /[A-Z]/.test(prop.key.name) && !prop.key.name.startsWith('on')) {
557 prop.key = t.identifier(lodash_1.snakeCase(prop.key.name));
558 }
559 }
560 }
561 }
562 },
563 AssignmentExpression(path) {
564 if (adapter_1.Adapter.type !== "quickapp" /* quickapp */) {
565 return;
566 }
567 const { left, right } = path.node;
568 if (t.isMemberExpression(left) && t.isIdentifier(left.property, { name: 'defaultProps' }) && t.isObjectExpression(right)) {
569 const props = right.properties;
570 for (const prop of props) {
571 if (t.isObjectProperty(prop)) {
572 if (t.isStringLiteral(prop.key) && /[A-Z]/.test(prop.key.value) && !prop.key.value.startsWith('on')) {
573 prop.key = t.stringLiteral(lodash_1.snakeCase(prop.key.value));
574 }
575 if (t.isIdentifier(prop.key) && /[A-Z]/.test(prop.key.name) && !prop.key.name.startsWith('on')) {
576 prop.key = t.identifier(lodash_1.snakeCase(prop.key.name));
577 }
578 }
579 }
580 }
581 },
582 ImportDeclaration(path) {
583 const source = path.node.source.value;
584 if (importSources.has(source)) {
585 throw utils_1.codeFrameError(path.node, '无法在同一文件重复 import 相同的包。');
586 }
587 else {
588 importSources.add(source);
589 }
590 const names = [];
591 if (source === constant_1.COMPONENTS_PACKAGE_NAME && "quickapp" /* quickapp */ === adapter_1.Adapter.type) {
592 path.node.specifiers.forEach((s) => {
593 if (t.isImportSpecifier(s)) {
594 const originalName = s.imported.name;
595 if (constant_1.quickappComponentName.has(originalName)) {
596 const importedName = `Taro${originalName}`;
597 s.imported.name = importedName;
598 s.local.name = importedName;
599 }
600 }
601 });
602 }
603 if (source === constant_1.TARO_PACKAGE_NAME) {
604 isImportTaro = true;
605 path.node.specifiers.push(t.importSpecifier(t.identifier(constant_1.INTERNAL_SAFE_GET), t.identifier(constant_1.INTERNAL_SAFE_GET)), t.importSpecifier(t.identifier(constant_1.INTERNAL_GET_ORIGNAL), t.identifier(constant_1.INTERNAL_GET_ORIGNAL)), t.importSpecifier(t.identifier(constant_1.INTERNAL_INLINE_STYLE), t.identifier(constant_1.INTERNAL_INLINE_STYLE)), t.importSpecifier(t.identifier(constant_1.HANDLE_LOOP_REF), t.identifier(constant_1.HANDLE_LOOP_REF)), t.importSpecifier(t.identifier(constant_1.GEN_COMP_ID), t.identifier(constant_1.GEN_COMP_ID)), t.importSpecifier(t.identifier(constant_1.GEN_LOOP_COMPID), t.identifier(constant_1.GEN_LOOP_COMPID)));
606 if (adapter_1.Adapter.type !== "alipay" /* alipay */) {
607 path.node.specifiers.push(t.importSpecifier(t.identifier(constant_1.PROPS_MANAGER), t.identifier(constant_1.PROPS_MANAGER)));
608 }
609 }
610 if (source === constant_1.REDUX_PACKAGE_NAME || source === constant_1.MOBX_PACKAGE_NAME) {
611 path.node.specifiers.forEach((s, index, specs) => {
612 if (s.local.name === 'Provider') {
613 specs.splice(index, 1);
614 specs.push(t.importSpecifier(t.identifier('setStore'), t.identifier('setStore')));
615 if (source === constant_1.REDUX_PACKAGE_NAME) {
616 hasReduxBinding = true;
617 specs.push(t.importSpecifier(t.identifier('ReduxContext'), t.identifier('ReduxContext')));
618 }
619 }
620 });
621 }
622 path.traverse({
623 ImportDefaultSpecifier(path) {
624 const name = path.node.local.name;
625 names.push(name);
626 },
627 ImportSpecifier(path) {
628 const name = path.node.imported.name;
629 names.push(name);
630 if (source === constant_1.TARO_PACKAGE_NAME && name === 'Component') {
631 path.node.local = t.identifier('__BaseComponent');
632 }
633 }
634 });
635 componentSourceMap.set(source, names);
636 }
637 });
638 if (!isImportTaro) {
639 const specifiers = [
640 t.importDefaultSpecifier(t.identifier('Taro')),
641 t.importSpecifier(t.identifier(constant_1.INTERNAL_SAFE_GET), t.identifier(constant_1.INTERNAL_SAFE_GET)),
642 t.importSpecifier(t.identifier(constant_1.INTERNAL_GET_ORIGNAL), t.identifier(constant_1.INTERNAL_GET_ORIGNAL)),
643 t.importSpecifier(t.identifier(constant_1.INTERNAL_INLINE_STYLE), t.identifier(constant_1.INTERNAL_INLINE_STYLE)),
644 t.importSpecifier(t.identifier(constant_1.HANDLE_LOOP_REF), t.identifier(constant_1.HANDLE_LOOP_REF)),
645 t.importSpecifier(t.identifier(constant_1.GEN_COMP_ID), t.identifier(constant_1.GEN_COMP_ID)),
646 t.importSpecifier(t.identifier(constant_1.GEN_LOOP_COMPID), t.identifier(constant_1.GEN_LOOP_COMPID))
647 ];
648 if (adapter_1.Adapter.type !== "alipay" /* alipay */) {
649 specifiers.push(t.importSpecifier(t.identifier(constant_1.PROPS_MANAGER), t.identifier(constant_1.PROPS_MANAGER)));
650 }
651 ast.program.body.unshift(t.importDeclaration(specifiers, t.stringLiteral('@tarojs/taro')));
652 }
653 if (!mainClass) {
654 throw new Error('未找到 Taro.Component 的类定义');
655 }
656 if (adapter_1.Adapter.type === "alipay" /* alipay */) {
657 const body = ast.program.body;
658 for (const i in body) {
659 if (t.isImportDeclaration(body[i]) && !t.isImportDeclaration(body[Number(i) + 1])) {
660 body.splice(Number(i) + 1, 0, t.variableDeclaration('const', [t.variableDeclarator(t.identifier('propsManager'), t.memberExpression(t.identifier('my'), t.identifier('propsManager')))]));
661 break;
662 }
663 }
664 }
665 mainClass.node.body.body.forEach(handleThirdPartyComponent);
666 const storeBinding = mainClass.scope.getBinding(storeName);
667 mainClass.scope.rename('Component', '__BaseComponent');
668 if (storeBinding) {
669 const statementPath = storeBinding.path.getStatementParent();
670 if (statementPath) {
671 ast.program.body.every((node, index, body) => {
672 if (node === statementPath.node) {
673 const settingReduxProvider = t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('ReduxContext'), t.identifier('Provider')), [
674 t.objectExpression([
675 t.objectProperty(t.identifier('store'), t.identifier(storeName))
676 ])
677 ]));
678 const ifStem = t.ifStatement(t.memberExpression(t.identifier('ReduxContext'), t.identifier('Provider')), t.blockStatement([
679 settingReduxProvider,
680 settingReduxProvider // 第一次调用初始化,第二次赋值
681 ]));
682 body.splice(index + 1, 0, t.expressionStatement(t.callExpression(t.identifier('setStore'), [
683 t.identifier(storeName)
684 ])), hasReduxBinding ? ifStem : t.emptyStatement());
685 return false;
686 }
687 return true;
688 });
689 }
690 }
691 resetTSClassProperty(mainClass.node.body.body);
692 if (options.isApp) {
693 renderMethod.replaceWith(t.classMethod('method', t.identifier('_createData'), [], t.blockStatement([])));
694 return { ast };
695 }
696 result = new class_1.Transformer(mainClass, options.sourcePath, componentProperies, options.sourceDir, classMethods).result;
697 result.code = babel_generator_1.default(ast).code;
698 result.ast = ast;
699 const lessThanSignReg = new RegExp(constant_1.lessThanSignPlacehold, 'g');
700 result.compressedTemplate = result.template.replace(lessThanSignReg, '<');
701 result.template = html_1.prettyPrint(result.template, {
702 max_char: 0,
703 unformatted: env_1.isTestEnv ? [] : ['text']
704 });
705 result.template = result.template.replace(lessThanSignReg, '<');
706 result.imageSrcs = Array.from(imageSource);
707 return result;
708}
709exports.default = transform;
710//# sourceMappingURL=index.js.map
\No newline at end of file