1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const babel_generator_1 = require("babel-generator");
|
4 | const t = require("babel-types");
|
5 | const lodash_1 = require("lodash");
|
6 | const constant_1 = require("./constant");
|
7 | const create_html_element_1 = require("./create-html-element");
|
8 | const utils_1 = require("./utils");
|
9 | const adapter_1 = require("./adapter");
|
10 | const functional_1 = require("./functional");
|
11 | const options_1 = require("./options");
|
12 | function isStartWithWX(str) {
|
13 | return str[0] === 'w' && str[1] === 'x';
|
14 | }
|
15 | exports.isStartWithWX = isStartWithWX;
|
16 | const specialComponentName = ['block', 'Block', 'slot', 'Slot'];
|
17 | function removeJSXThisProperty(path) {
|
18 | if (!path.parentPath.isCallExpression()) {
|
19 | const p = path.getSibling('property');
|
20 | if (p.isIdentifier({ name: 'props' }) ||
|
21 | p.isIdentifier({ name: 'state' })) {
|
22 | path.parentPath.replaceWithSourceString('this');
|
23 | }
|
24 | else {
|
25 | path.parentPath.replaceWith(p);
|
26 | }
|
27 | }
|
28 | }
|
29 | exports.removeJSXThisProperty = removeJSXThisProperty;
|
30 | function findJSXAttrByName(attrs, name) {
|
31 | for (const attr of attrs) {
|
32 | if (!t.isJSXAttribute(attr))
|
33 | continue;
|
34 | if (!t.isJSXIdentifier(attr.name)) {
|
35 | break;
|
36 | }
|
37 | if (attr.name.name === name) {
|
38 | return attr;
|
39 | }
|
40 | }
|
41 | return null;
|
42 | }
|
43 | exports.findJSXAttrByName = findJSXAttrByName;
|
44 | function buildRefTemplate(name, refName, loop, key) {
|
45 | const isSwan = adapter_1.Adapter.type === "swan" ;
|
46 | const dataString = isSwan ? `{{{...${refName ? `${loop ? '' : '$$'}${refName}` : '__data'}}}}` : `{{...${refName ? `${loop ? '' : '$$'}${refName}` : '__data'}}}`;
|
47 | const attrs = [
|
48 | t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)),
|
49 | t.jSXAttribute(t.jSXIdentifier('data'), t.stringLiteral(dataString))
|
50 | ];
|
51 | if (key) {
|
52 | attrs.push(key);
|
53 | }
|
54 | return t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('template'), attrs), t.jSXClosingElement(t.jSXIdentifier('template')), []);
|
55 | }
|
56 | exports.buildRefTemplate = buildRefTemplate;
|
57 | function buildJSXAttr(name, value) {
|
58 | return t.jSXAttribute(t.jSXIdentifier(name), t.jSXExpressionContainer(value));
|
59 | }
|
60 | exports.buildJSXAttr = buildJSXAttr;
|
61 | function newJSXIfAttr(jsx, value) {
|
62 | jsx.openingElement.attributes.push(buildJSXAttr(adapter_1.Adapter.if, value));
|
63 | }
|
64 | exports.newJSXIfAttr = newJSXIfAttr;
|
65 | function setJSXAttr(jsx, name, value, path) {
|
66 | if ((name === adapter_1.Adapter.forIndex || name === adapter_1.Adapter.forItem) && adapter_1.Adapter.type === "quickapp" ) {
|
67 | return;
|
68 | }
|
69 | const element = jsx.openingElement;
|
70 |
|
71 | if (element == null || !t.isJSXIdentifier(element.name)) {
|
72 | return;
|
73 | }
|
74 | if (element.name.name === 'Block' || element.name.name === 'block' || !path) {
|
75 | jsx.openingElement.attributes.push(t.jSXAttribute(t.jSXIdentifier(name), value));
|
76 | }
|
77 | else {
|
78 | const block = buildBlockElement();
|
79 | setJSXAttr(block, name, value);
|
80 | block.children = [jsx];
|
81 | path.node = block;
|
82 | }
|
83 | }
|
84 | exports.setJSXAttr = setJSXAttr;
|
85 | function buildTrueJSXAttrValue() {
|
86 | return t.jSXExpressionContainer(t.booleanLiteral(true));
|
87 | }
|
88 | exports.buildTrueJSXAttrValue = buildTrueJSXAttrValue;
|
89 | function generateJSXAttr(ast) {
|
90 | const code = utils_1.decodeUnicode(babel_generator_1.default(ast, {
|
91 | quotes: 'single',
|
92 | jsonCompatibleStrings: true
|
93 | }).code)
|
94 | .replace(/</g, constant_1.lessThanSignPlacehold);
|
95 | if (functional_1.Status.isSFC) {
|
96 | return code;
|
97 | }
|
98 | return code.replace(/(this\.props\.)|(this\.state\.)/g, '')
|
99 | .replace(/(props\.)|(state\.)/g, '')
|
100 | .replace(/this\./g, '');
|
101 | }
|
102 | exports.generateJSXAttr = generateJSXAttr;
|
103 | function isAllLiteral(...args) {
|
104 | return args.every(p => t.isLiteral(p));
|
105 | }
|
106 | exports.isAllLiteral = isAllLiteral;
|
107 | function buildBlockElement(attrs = [], isView = false) {
|
108 | let blockName = adapter_1.Adapter.type === "quickapp" ? 'div' : 'block';
|
109 | if (isView) {
|
110 | blockName = 'View';
|
111 | }
|
112 | return t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier(blockName), attrs), t.jSXClosingElement(t.jSXIdentifier(blockName)), []);
|
113 | }
|
114 | exports.buildBlockElement = buildBlockElement;
|
115 | function parseJSXChildren(children) {
|
116 | return children
|
117 | .reduce((str, child) => {
|
118 | if (t.isJSXText(child)) {
|
119 | const strings = [];
|
120 | child.value.split(/(\r?\n\s*)/).forEach((val) => {
|
121 | const value = val
|
122 | .replace(/\u00a0/g, ' ')
|
123 | .replace(/\u2002/g, ' ')
|
124 | .replace(/\u2003/g, ' ');
|
125 | if (!value) {
|
126 | return;
|
127 | }
|
128 | if (value.startsWith('\n')) {
|
129 | return;
|
130 | }
|
131 | strings.push(value);
|
132 | });
|
133 | return str + strings.join('');
|
134 | }
|
135 | if (t.isJSXElement(child)) {
|
136 | return str + parseJSXElement(child);
|
137 | }
|
138 | if (t.isJSXExpressionContainer(child)) {
|
139 | if (t.isJSXElement(child.expression)) {
|
140 | return str + parseJSXElement(child.expression);
|
141 | }
|
142 | return str + `{${generateJSXAttr(child)}}`;
|
143 | }
|
144 | return str;
|
145 | }, '');
|
146 | }
|
147 | function parseJSXElement(element, isFirstEmit = false) {
|
148 | const children = element.children;
|
149 | const { attributes, name } = element.openingElement;
|
150 | const TRIGGER_OBSERER = adapter_1.Adapter.type === "swan" || adapter_1.Adapter.type === "quickapp" ? 'privateTriggerObserer' : '__triggerObserer';
|
151 | const TRIGGER_OBSERER_KEY = adapter_1.Adapter.type === "quickapp" ? 'privateTriggerObsererKey' : '_triggerObserer';
|
152 | if (t.isJSXMemberExpression(name)) {
|
153 | throw utils_1.codeFrameError(name.loc, '暂不支持 JSX 成员表达式');
|
154 | }
|
155 | const componentName = name.name;
|
156 | const isDefaultComponent = constant_1.DEFAULT_Component_SET.has(componentName);
|
157 | const componentSpecialProps = constant_1.SPECIAL_COMPONENT_PROPS.get(componentName);
|
158 | const componentTransfromProps = constant_1.TRANSFORM_COMPONENT_PROPS.get(adapter_1.Adapter.type);
|
159 | let hasElseAttr = false;
|
160 | const isJSXMetHod = componentName === 'Template' && attributes.some(a => a.name.name === 'is' && t.isStringLiteral(a.value) && a.value.value.startsWith('render'));
|
161 | attributes.forEach((a, index) => {
|
162 | if (t.isJSXAttribute(a) && a.name.name === adapter_1.Adapter.else && !['block', 'Block'].includes(componentName) && !isDefaultComponent) {
|
163 | hasElseAttr = true;
|
164 | attributes.splice(index, 1);
|
165 | }
|
166 | });
|
167 | if (hasElseAttr) {
|
168 | return create_html_element_1.createHTMLElement({
|
169 | name: 'block',
|
170 | attributes: {
|
171 | [adapter_1.Adapter.else]: true
|
172 | },
|
173 | value: parseJSXChildren([element])
|
174 | });
|
175 | }
|
176 | let attributesTrans = {};
|
177 | if (attributes.length) {
|
178 | attributesTrans = attributes.reduce((obj, attr) => {
|
179 | if (t.isJSXSpreadAttribute(attr)) {
|
180 | if (adapter_1.isNewPropsSystem())
|
181 | return {};
|
182 | throw utils_1.codeFrameError(attr.loc, 'JSX 参数暂不支持 ...spread 表达式');
|
183 | }
|
184 | let name = attr.name.name;
|
185 | if (constant_1.DEFAULT_Component_SET.has(componentName)) {
|
186 | if (name === 'className') {
|
187 | name = 'class';
|
188 | }
|
189 | if (typeof name === 'string' && /(^on[A-Z_])|(^catch[A-Z_])/.test(name) && adapter_1.Adapter.type === "quickapp" ) {
|
190 | name = name.toLowerCase();
|
191 | }
|
192 | }
|
193 | if ("quickapp" === adapter_1.Adapter.type && !constant_1.DEFAULT_Component_SET_COPY.has(componentName) && typeof name === 'string' && !/(^on[A-Z_])|(^catch[A-Z_])/.test(name)) {
|
194 | name = lodash_1.snakeCase(name);
|
195 | }
|
196 | let value = true;
|
197 | let attrValue = attr.value;
|
198 | if (typeof name === 'string') {
|
199 | const isAlipayOrQuickappEvent = (adapter_1.Adapter.type === "alipay" || adapter_1.Adapter.type === "quickapp" ) && /(^on[A-Z_])|(^catch[A-Z_])/.test(name);
|
200 | if (t.isStringLiteral(attrValue)) {
|
201 | value = attrValue.value;
|
202 | }
|
203 | else if (t.isJSXExpressionContainer(attrValue)) {
|
204 | let isBindEvent = (name.startsWith('bind') && name !== 'bind') || (name.startsWith('catch') && name !== 'catch');
|
205 | let code = utils_1.decodeUnicode(babel_generator_1.default(attrValue.expression, {
|
206 | quotes: 'single',
|
207 | concise: true
|
208 | }).code)
|
209 | .replace(/"/g, "'")
|
210 | .replace(/(this\.props\.)|(this\.state\.)/g, '')
|
211 | .replace(/this\./g, '');
|
212 | if ("swan" === adapter_1.Adapter.type &&
|
213 | code !== 'true' &&
|
214 | code !== 'false' &&
|
215 | constant_1.swanSpecialAttrs[componentName] &&
|
216 | constant_1.swanSpecialAttrs[componentName].includes(name)) {
|
217 | value = `{= ${code} =}`;
|
218 | }
|
219 | else {
|
220 | if (adapter_1.Adapter.key === name) {
|
221 | const splitCode = code.split('.');
|
222 | if (splitCode.length > 1) {
|
223 | value = splitCode.slice(1).join('.');
|
224 | }
|
225 | else {
|
226 | value = code;
|
227 | }
|
228 | }
|
229 | else {
|
230 | const isTemplateData = isJSXMetHod && name === 'data';
|
231 | value = isBindEvent || isAlipayOrQuickappEvent ? code : `{{${isJSXMetHod && name === 'data' ? '...' : ''}${code}}}`;
|
232 | if (isTemplateData && "swan" === adapter_1.Adapter.type) {
|
233 | value = `{${value}}`;
|
234 | }
|
235 | }
|
236 | }
|
237 | if (adapter_1.Adapter.type === "swan" && name === adapter_1.Adapter.for) {
|
238 | value = code;
|
239 | }
|
240 | if (t.isStringLiteral(attrValue.expression)) {
|
241 | value = attrValue.expression.value;
|
242 | }
|
243 |
|
244 | }
|
245 | else if (attrValue === null && name !== adapter_1.Adapter.else) {
|
246 | value = `{{true}}`;
|
247 | }
|
248 | if (constant_1.THIRD_PARTY_COMPONENTS.has(componentName) && /^bind/.test(name) && name.includes('-')) {
|
249 | name = name.replace(/^bind/, 'bind:');
|
250 | }
|
251 | if (componentTransfromProps && componentTransfromProps[componentName]) {
|
252 | const transfromProps = componentTransfromProps[componentName];
|
253 | Object.keys(transfromProps).forEach(oriName => {
|
254 | if (name === oriName) {
|
255 | name = transfromProps[oriName];
|
256 | }
|
257 | });
|
258 | }
|
259 | if ((componentName === 'Input' || componentName === 'input') && name === 'maxLength') {
|
260 | obj['maxlength'] = value;
|
261 | }
|
262 | else if ((componentSpecialProps && componentSpecialProps.has(name)) ||
|
263 | name.startsWith(constant_1.FN_PREFIX) ||
|
264 | isAlipayOrQuickappEvent) {
|
265 | obj[name] = value;
|
266 | }
|
267 | else {
|
268 | obj[isDefaultComponent && !name.includes('-') && !name.includes(':') ? lodash_1.kebabCase(name) : name] = value;
|
269 | }
|
270 | }
|
271 | if (!isDefaultComponent && !specialComponentName.includes(componentName) && !adapter_1.isNewPropsSystem()) {
|
272 | obj[TRIGGER_OBSERER] = `{{ ${TRIGGER_OBSERER_KEY} }}`;
|
273 | }
|
274 | return obj;
|
275 | }, {});
|
276 | }
|
277 | else if (!isDefaultComponent && !specialComponentName.includes(componentName)) {
|
278 | if (!adapter_1.isNewPropsSystem()) {
|
279 | attributesTrans[TRIGGER_OBSERER] = `{{ ${TRIGGER_OBSERER_KEY} }}`;
|
280 | }
|
281 | }
|
282 | let elementStr;
|
283 | if (isFirstEmit && "quickapp" === adapter_1.Adapter.type && !options_1.transformOptions.isRoot) {
|
284 | const rootAttributes = Object.assign({}, attributesTrans);
|
285 | delete rootAttributes[adapter_1.Adapter.if];
|
286 | elementStr = create_html_element_1.createHTMLElement({
|
287 | name: lodash_1.kebabCase(componentName),
|
288 | attributes: rootAttributes,
|
289 | value: create_html_element_1.createHTMLElement({
|
290 | name: 'block',
|
291 | attributes: { [adapter_1.Adapter.if]: attributesTrans[adapter_1.Adapter.if] },
|
292 | value: parseJSXChildren(children)
|
293 | })
|
294 | }, isFirstEmit);
|
295 | }
|
296 | else {
|
297 | elementStr = create_html_element_1.createHTMLElement({
|
298 | name: lodash_1.kebabCase(componentName),
|
299 | attributes: attributesTrans,
|
300 | value: parseJSXChildren(children)
|
301 | }, isFirstEmit);
|
302 | }
|
303 | return elementStr;
|
304 | }
|
305 | exports.parseJSXElement = parseJSXElement;
|
306 | function generateHTMLTemplate(template, name) {
|
307 | return create_html_element_1.createHTMLElement({
|
308 | name: 'template',
|
309 | attributes: {
|
310 | name
|
311 | },
|
312 | value: parseJSXElement(template)
|
313 | });
|
314 | }
|
315 | exports.generateHTMLTemplate = generateHTMLTemplate;
|
316 |
|
\ | No newline at end of file |