UNPKG

14 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const babel_generator_1 = require("babel-generator");
4const t = require("babel-types");
5const lodash_1 = require("lodash");
6const constant_1 = require("./constant");
7const create_html_element_1 = require("./create-html-element");
8const utils_1 = require("./utils");
9const adapter_1 = require("./adapter");
10const functional_1 = require("./functional");
11const options_1 = require("./options");
12function isStartWithWX(str) {
13 return str[0] === 'w' && str[1] === 'x';
14}
15exports.isStartWithWX = isStartWithWX;
16const specialComponentName = ['block', 'Block', 'slot', 'Slot'];
17function 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}
29exports.removeJSXThisProperty = removeJSXThisProperty;
30function 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}
43exports.findJSXAttrByName = findJSXAttrByName;
44function buildRefTemplate(name, refName, loop, key) {
45 const isSwan = adapter_1.Adapter.type === "swan" /* 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}
56exports.buildRefTemplate = buildRefTemplate;
57function buildJSXAttr(name, value) {
58 return t.jSXAttribute(t.jSXIdentifier(name), t.jSXExpressionContainer(value));
59}
60exports.buildJSXAttr = buildJSXAttr;
61function newJSXIfAttr(jsx, value) {
62 jsx.openingElement.attributes.push(buildJSXAttr(adapter_1.Adapter.if, value));
63}
64exports.newJSXIfAttr = newJSXIfAttr;
65function setJSXAttr(jsx, name, value, path) {
66 if ((name === adapter_1.Adapter.forIndex || name === adapter_1.Adapter.forItem) && adapter_1.Adapter.type === "quickapp" /* quickapp */) {
67 return;
68 }
69 const element = jsx.openingElement;
70 // tslint:disable-next-line: strict-type-predicates
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}
84exports.setJSXAttr = setJSXAttr;
85function buildTrueJSXAttrValue() {
86 return t.jSXExpressionContainer(t.booleanLiteral(true));
87}
88exports.buildTrueJSXAttrValue = buildTrueJSXAttrValue;
89function 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}
102exports.generateJSXAttr = generateJSXAttr;
103function isAllLiteral(...args) {
104 return args.every(p => t.isLiteral(p));
105}
106exports.isAllLiteral = isAllLiteral;
107function buildBlockElement(attrs = [], isView = false) {
108 let blockName = adapter_1.Adapter.type === "quickapp" /* 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}
114exports.buildBlockElement = buildBlockElement;
115function 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, '&nbsp;')
123 .replace(/\u2002/g, '&ensp;')
124 .replace(/\u2003/g, '&emsp;');
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}
147function parseJSXElement(element, isFirstEmit = false) {
148 const children = element.children;
149 const { attributes, name } = element.openingElement;
150 const TRIGGER_OBSERER = adapter_1.Adapter.type === "swan" /* swan */ || adapter_1.Adapter.type === "quickapp" /* quickapp */ ? 'privateTriggerObserer' : '__triggerObserer';
151 const TRIGGER_OBSERER_KEY = adapter_1.Adapter.type === "quickapp" /* 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" /* quickapp */) {
190 name = name.toLowerCase();
191 }
192 }
193 if ("quickapp" /* 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" /* alipay */ || adapter_1.Adapter.type === "quickapp" /* 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" /* 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" /* swan */ === adapter_1.Adapter.type) {
233 value = `{${value}}`;
234 }
235 }
236 }
237 if (adapter_1.Adapter.type === "swan" /* swan */ && name === adapter_1.Adapter.for) {
238 value = code;
239 }
240 if (t.isStringLiteral(attrValue.expression)) {
241 value = attrValue.expression.value;
242 }
243 // tslint:disable-next-line: strict-type-predicates
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" /* 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}
305exports.parseJSXElement = parseJSXElement;
306function generateHTMLTemplate(template, name) {
307 return create_html_element_1.createHTMLElement({
308 name: 'template',
309 attributes: {
310 name
311 },
312 value: parseJSXElement(template)
313 });
314}
315exports.generateHTMLTemplate = generateHTMLTemplate;
316//# sourceMappingURL=jsx.js.map
\No newline at end of file