function visitStartIfTag(traverse, object, path, state) { hasElse = false; var attributes = object.attributes; if (!attributes || !attributes.length) { throw new Error(errors.IF_WITH_NO_CONDITION); } var condition = _.find(attributes, function (attr) { return attr.name.name === 'condition' }); if (!condition) { throw new Error(errors.IF_WITH_NO_CONDITION); } if (shouldWrapCurlyBrackets()) { utils.append('{ ', state); } utils.move(condition.value.expression.range[0], state); utils.catchup(condition.value.expression.range[1], state); utils.append(' ? (', state); utils.move(object.range[1], state); inControlStatement = true; }
function visitTypedFunction(traverse, node, path, state) { var klass = getParentClassDeclaration(path); var generics = klass && klass.typeParameters ? toLookup(klass.typeParameters.params.map(getName)) : {}; if (node.typeParameters) { generics = mixin(generics, toLookup(node.typeParameters.params.map(getName))); } var ctx = new Context(state, generics); var rest = node.rest ? ', ' + ctx.getType(node.rest.typeAnnotation.typeAnnotation) : ''; var types = []; var params = []; node.params.forEach(function (param) { var type = ctx.getType(param.typeAnnotation ? param.typeAnnotation.typeAnnotation : null); types.push(param.optional ? ctx.getProperty('optional') + '(' + type + ')' : type); params.push(param.name); }); utils.catchup(node.body.range[0] + 1, state); if (params.length || rest) { utils.append(ctx.getProperty('check') + '(arguments, ' + ctx.getProperty('arguments') + '([' + types.join(', ') + ']' + rest + '));', state); } if (node.returnType) { var returnType = ctx.getType(node.returnType.typeAnnotation); utils.append(' var ret = (function (' + params.join(', ') + ') {', state); traverse(node.body, path, state); utils.catchup(node.body.range[1] - 1, state); utils.append('}).apply(this, arguments); return ' + ctx.getProperty('check') + '(ret, ' + returnType + ');', state); } else { traverse(node.body, path, state); } return false; }
attributes.forEach(function(attr, index) { var isLast = (index === (attributes.length - 1)); var name = attr.name.name; utils.catchup(attr.range[0], state, trimLeft); var displayName = name; if (name in options.renameAttrs) { displayName = options.renameAttrs[name]; } utils.append(quoteJSObjKey(displayName) + ': ', state); if (attr.value) { utils.move(attr.name.range[1], state); utils.catchupNewlines(attr.value.range[0], state); if (attr.value.type === Syntax.Literal) { renderJSXLiteral(attr.value, isLast, state); } else { renderJSXExpressionContainer(traverse, attr.value, isLast, path, state); } } else { state.g.buffer += 'true'; state.g.position = attr.name.range[1]; if (!isLast) { utils.append(', ', state); } } utils.catchup(attr.range[1], state, trimLeft); });
function visitStartForTag(traverse, object, path, state) { var attributes = object.attributes; if (!attributes || !attributes.length) { throw new Error(errors.FOR_WITH_NO_ATTRIBUTES); } var each, of; attributes.forEach(function (attr) { if (attr.name.name === 'each') { each = attr; } else if (attr.name.name === 'of') { of = attr; } }); if (!each || !of) { throw new Error(errors.FOR_WITH_NO_ATTRIBUTES); } if (shouldWrapCurlyBrackets()) { utils.append('{ ', state); } utils.move(of.value.expression.range[0], state); utils.catchup(of.value.expression.range[1], state); utils.append('.map(function(', state); utils.move(each.value.range[0] + 1, state); utils.catchup(each.value.range[1] - 1, state); utils.append(', $index) { return (', state); utils.move(object.range[1], state) inControlStatement = true; }
// In: x = {class: 2}; // Out: x = {"class": 2}; function visitProperty(traverse, node, path, state) { utils.catchup(node.key.range[0], state); utils.append('"', state); utils.catchup(node.key.range[1], state); utils.append('"', state); utils.catchup(node.value.range[0], state); traverse(node.value, path, state); return false; }
function visitEndForTag(traverse, object, path, state) { utils.append(')}, this)', state); if (shouldWrapCurlyBrackets()) { utils.append('}', state); } utils.move(object.range[1], state); contextStack.pop(); }
// In: x.class = 3; // Out: x["class"] = 3; function visitMemberExpression(traverse, node, path, state) { traverse(node.object, path, state); utils.catchup(node.object.range[1], state); utils.append('[', state); utils.catchupWhiteSpace(node.property.range[0], state); utils.append('"', state); utils.catchup(node.property.range[1], state); utils.append('"]', state); return false; }
function visitEndIfTag(traverse, object, path, state) { utils.catchup(object.range[0], state); utils.append(hasElse ? ')' : ') : \'\'', state); if (shouldWrapCurlyBrackets()) { utils.append(' }', state); } utils.move(object.range[1], state); contextStack.pop(); }
function visitTypedVariableDeclarator(traverse, node, path, state) { var ctx = new Context(state); if (node.init) { utils.catchup(node.init.range[0], state); utils.append(ctx.getProperty('check') + '(', state); traverse(node.init, path, state); utils.catchup(node.init.range[1], state); utils.append(', ' + ctx.getType(node.id.typeAnnotation.typeAnnotation) + ')', state); } utils.catchup(node.range[1], state); return false; }
function visitFunctionBodyWithRestParam(traverse, node, path, state) { utils.catchup(node.range[0] + 1, state); var parentNode = path[0]; utils.append(renderRestParamSetup(parentNode), state); traverse(node.body, path, state); return false; }
function addDisplayName(displayName, object, state) { if (object && object.type === Syntax.CallExpression && object.callee.type === Syntax.MemberExpression && object.callee.object.type === Syntax.Identifier && object.callee.object.name === 'React' && object.callee.property.type === Syntax.Identifier && object.callee.property.name === 'createClass' && object['arguments'].length === 1 && object['arguments'][0].type === Syntax.ObjectExpression) { // Verify that the displayName property isn't already set var properties = object['arguments'][0].properties; var safe = properties.every(function(property) { var value = property.key.type === Syntax.Identifier ? property.key.name : property.key.value; return value !== 'displayName'; }); if (safe) { utils.catchup(object['arguments'][0].range[0] + 1, state); utils.append("displayName: '" + displayName + "',", state); } } }
/** * Visit ImportDeclaration. * * Examples: * * import "module" * import name from "module" * import { name, one as other } from "module" */ function visitImportDeclaration(traverse, node, path, state) { var specifier, name; utils.catchup(node.range[0], state); switch (node.kind) { // import "module" case undefined: utils.append('require(' + node.source.raw + ');', state); break; // import name from "module" case "default": specifier = node.specifiers[0]; assert(specifier, "default import without specifier: " + node); name = specifier.name ? specifier.name.name : specifier.id.name; utils.append('var ' + name + ' = require(' + node.source.raw + ');', state); break; // import {name, one as other} from "module" case "named": var modID; if (node.specifiers.length === 1) { modID = 'require(' + node.source.raw + ')'; } else { modID = genID('mod'); utils.append('var ' + modID + ' = require(' + node.source.raw + ');', state); } for (var i = 0, len = node.specifiers.length; i < len; i++) { specifier = node.specifiers[i]; utils.catchupNewlines(specifier.range[0], state); name = specifier.name ? specifier.name.name : specifier.id.name; utils.append('var ' + name + ' = ' + modID + '.' + specifier.id.name + ';', state); } break; default: assert(false, "don't know how to transform: " + node.kind); } utils.catchupNewlines(node.range[1], state); utils.move(node.range[1], state); return false; }
function renderXJSLiteral(object, state) { var value = object.raw; utils.catchup(object.range[0], state); /* This can be used to "annotate spaces" inserted by this transformation, so that they can be more easily recognized as such in the final code {' '} {'\\x20'} {(' ')} {' '||0} {' '||AnyTextYouLike} {' '||'AnyTextYouLike'} {GlobalVariableWithASpace} */ var space = "{' '}"; /* · space ¬ newline {expr} = <tag> Old whitespace rules: {1}··Aaa··Bbb··{2}··{3} → {1}·Aaa··Bbb·{2}{3} {1}¬¬Aaa¬¬Bbb¬¬{2}¬¬{3} → {1}·Aaa·Bbb·{2}{3} New whitespace rules: {1}··Aaa··Bbb··{2}··{3} → {1}··Aaa··Bbb··{2}··{3} {1}¬¬Aaa¬¬Bbb¬¬{2}¬¬{3} → {1}Aaa·Bbb{2}{3} Required transformation: {1}··{2} = {1}··{2} → {1}{2} {1}··Aaa··{2} = {1}··Aaa··{2} → {1}·Aaa·{2} {1}¬¬Aaa¬¬{2} = {1}Aaa{2} → {1}·Aaa·{2} */ // {1}··{2} = {1}··{2} → {1}{2} value = value.replace(/^[ \t]+$/, ''); // {1}··Aaa··{2} = {1}··Aaa··{2} → {1}·Aaa·{2} value = value.replace(/^[ \t]+([^ \t\r\n])/, " $1"); value = value.replace(/([^ \t\r\n])[ \t]+$/, "$1 "); // {1}¬¬Aaa¬¬{2} = {1}Aaa{2} → {1}·Aaa·{2} value = value.replace(/^([ \t]*[\r\n][ \t\r\n]*)([^ \t\r\n].*)/, "$1" + space + "$2"); value = value.replace(/([^ \t\r\n])([ \t]*[\r\n][ \t\r\n]*)$/, "$1" + space + "$2"); // Rendered whitespace tabs are replaced with spaces value = value.replace(/[^ \t\r\n][ ]*[\t][ \t]*[^ \t\r\n]/, function(match) { return match.replace(/\t/g, ' '); }); utils.append(value, state); utils.move(object.range[1], state); }
lines.forEach(function (line, ii) { var lastLine = ii === numLines - 1; var trimmedLine = safeTrim(line); if (trimmedLine === '' && !lastLine) { append(line, state); } else { var preString = ''; var postString = ''; var leading = ''; if (ii === 0) { if (hasInitialNewLine) { preString = ' '; leading = '\n'; } if (trimmedChildValueWithSpace.substring(0, 1) === ' ') { // If this is the first line, and the original content starts with // whitespace, place a single space at the beginning. preString = ' '; } } else { leading = line.match(/^[ \t]*/)[0]; } if (!lastLine || trimmedChildValueWithSpace.substr( trimmedChildValueWithSpace.length - 1, 1) === ' ' || hasFinalNewLine ) { // If either not on the last line, or the original content ends with // whitespace, place a single character at the end. postString = ' '; } append( leading + JSON.stringify( preString + trimmedLine + postString ) + (lastLine ? '' : '+') + line.match(/[ \t]*$/)[0], state); } if (!lastLine) { append('\n', state); } });
function visitProgram(traverse, node, path, state) { var ctx = new Context(state); var namespace = ctx.namespace; // FIXME remove 2nd condition when flowcheck-loader will not use the namespace option if (!ctx.skipImport && namespace.indexOf('require') === -1) { utils.append('var ' + namespace + ' = require(' + JSON.stringify(ctx.module) + ');', state); } return true; }
var visitor = function visitRequireAssets(traverse, node, p, state) { var id = node.arguments[0].value; var result = registry.requireAssets(id, basedir); utils.catchup(node.range[0], state); utils.append(JSON.stringify(result), state); utils.move(node.range[1], state); };
/** * 当 visitGlobal.test 判断正确后,进出此逻辑 * * 用来将 global.xxx 换成 window.xxx * * @param {Function} traverse 可用来继续处理子节点。 * @param {Object} node 当前节点。 * @param {Array} path 路径数组,包含进入该节点前的父级节点。 * @param {Object} state state 对象,用来保存对 node 修改状态。 * @return {boolean} false [description] */ function visitGlobal(traverse, node, path, state) { // 如果当前 scope 中存在 global 变量,则忽略。 if (util.existsVariable(path, node)) { return false; } utils.catchup(node.range[0], state); utils.append('window', state); utils.move(node.range[1], state); return false; }
function visitProcessEnv(traverse, node, path, state) { var key = node.property.name for (var i = 0; i < envs.length; i++) { var value = envs[i][key] if (value !== undefined) { utils.catchup(node.range[0], state) utils.append(JSON.stringify(value), state) utils.move(node.range[1], state) return false } } return false }
function renderXJSExpressionContainer(traverse, object, isLast, path, state) { // Plus 1 to skip `{`. move(object.range[0] + 1, state); traverse(object.expression, path, state); if (!isLast && object.expression.type !== Syntax.XJSEmptyExpression) { // If we need to append a comma, make sure to do so after the expression. catchup(object.expression.range[1], state); append(',', state); } // Minus 1 to skip `}`. catchup(object.range[1] - 1, state); move(object.range[1], state); return false; }
childrenToRender.forEach(function (child, index) { utils.catchup(child.range[0], state, trimLeft); var isLast = index >= lastRenderableIndex; if (child.type === Syntax.Literal) { renderXJSLiteral(child, isLast, state); } else if (child.type === Syntax.XJSExpressionContainer) { renderXJSExpressionContainer(traverse, child, isLast, path, state); } else { traverse(child, path, state); if (!isLast) { utils.append(', ', state); } } utils.catchup(child.range[1], state, trimLeft); });
attributesObject.forEach(function(attr, index) { utils.catchup(attr.range[0], state); if (attr.name.namespace) { throw new Error( 'Namespace attributes are not supported. ReactJSX is not XML.'); } var name = attr.name.name; var isFirst = index === 0; var isLast = index === attributesObject.length - 1; if (isFirst) { utils.append('{', state); } utils.append(quoteAttrName(name), state); utils.append(':', state); if (!attr.value) { state.g.buffer += 'true'; state.g.position = attr.name.range[1]; if (!isLast) { utils.append(',', state); } } else { utils.move(attr.name.range[1], state); // Use catchupWhiteSpace to skip over the '=' in the attribute utils.catchupWhiteSpace(attr.value.range[0], state); if (JSX_ATTRIBUTE_TRANSFORMS[attr.name.name]) { utils.append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state); utils.move(attr.value.range[1], state); if (!isLast) { utils.append(',', state); } } else if (attr.value.type === Syntax.Literal) { renderXJSLiteral(attr.value, isLast, state); } else { renderXJSExpressionContainer(traverse, attr.value, isLast, path, state); } } if (isLast) { utils.append('}', state); } utils.catchup(attr.range[1], state); });
childrenToRender.forEach(function(child, index) { utils.catchup(child.range[0], state); var isLast = index === childrenToRender.length - 1; if (child.type === Syntax.Literal) { renderXJSLiteral(child, isLast, state); } else if (child.type === Syntax.XJSExpressionContainer) { renderXJSExpressionContainer(traverse, child, isLast, path, state); } else { traverse(child, path, state); if (!isLast) { utils.append(',', state); state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1'); } } utils.catchup(child.range[1], state); });
function renderXJSExpressionContainer( traverse, object, isNotAfterLiteral, isNotBeforeLiteral, path, state) { utils.catchup(object.range[0], state); // Unbox the previously required {' '}-workaround var raw = object.expression.raw; var isSpace = (raw === "' '" || raw === '" "'); if (isNotAfterLiteral && isNotBeforeLiteral && isSpace) { utils.append(' ', state); utils.move(object.range[1], state); } else { utils.catchup(object.range[1], state); } return false; }
lines.forEach(function (line, index) { var isFirstLine = index === 0; var isLastLine = index === lines.length - 1; var isLastNonEmptyLine = index === lastNonEmptyLine; // replace rendered whitespace tabs with spaces var trimmedLine = line.replace(/\t/g, ' '); // trim whitespace touching a newline if (!isFirstLine) { trimmedLine = trimmedLine.replace(/^[ ]+/, ''); } if (!isLastLine) { trimmedLine = trimmedLine.replace(/[ ]+$/, ''); } if (!isFirstLine) { utils.append(line.match(/^[ \t]*/)[0], state); } if (trimmedLine || isLastNonEmptyLine) { utils.append( JSON.stringify(trimmedLine) + (!isLastNonEmptyLine ? " + ' ' +" : ''), state); if (isLastNonEmptyLine) { if (end) { utils.append(end, state); } if (!isLast) { utils.append(', ', state); } } // only restore tail whitespace if line had literals if (trimmedLine && !isLastLine) { utils.append(line.match(/[ \t]*$/)[0], state); } } if (!isLastLine) { utils.append('\n', state); } });
function visitElseTag(traverse, object, path, state) { hasElse = true; utils.catchup(object.range[0], state); utils.append(') : (', state); utils.move(object.range[1], state); }
/** * Visit tag node and desugar JSX. * * @see {@link https://github.com/facebook/jstransform} * @param {Function} traverse * @param {Object} object * @param {String} path * @param {Object} state * @returns {Boolean} * @private */ function visitNode(traverse, object, path, state) { var options = state.g.opts; var factory = (options.factory); var arrayChildren = options.arrayChildren var openingEl = object.openingElement; var closingEl = object.closingElement; var nameObj = openingEl.name; var attributes = openingEl.attributes; var spreadFn = options.spreadFn; var unknownTagPattern = options.unknownTagPattern; if (!options.renameAttrs) { options.renameAttrs = {}; } utils.catchup(openingEl.range[0], state, trimLeft); var tagName = nameObj.name; var isJSXIdentifier = nameObj.type === Syntax.JSXIdentifier; var knownTag = tagName[0] !== tagName[0].toUpperCase() && isJSXIdentifier; var hasAtLeastOneSpreadAttribute = attributes.some(function (attr) { return attr.type === Syntax.JSXSpreadAttribute; }); var secondArg = false; if (knownTag) { utils.append(factory + "('", state); // DOM('div', ...) } else if (options.passUnknownTagsToFactory) { if (options.unknownTagsAsString) { utils.append(factory + "('", state); } else { utils.append(factory + '(', state); } } utils.move(nameObj.range[0], state); if (knownTag) { // DOM('div', ...) utils.catchup(nameObj.range[1], state); utils.append("'", state); secondArg = true } else if (options.passUnknownTagsToFactory) { // DOM(Component, ...) utils.catchup(nameObj.range[1], state); if (options.unknownTagsAsString) { utils.append("'", state); } secondArg = true } else { // Component(...) tagName = unknownTagPattern.replace('{tag}', nameObj.name); utils.append(tagName, state); utils.move( nameObj.range[1] + (tagName.length - nameObj.name.length), state ); utils.append('(', state); } if (hasAtLeastOneSpreadAttribute) { if (options.passUnknownTagsToFactory || knownTag) { utils.append(', ' + spreadFn + '({', state); } else { utils.append(spreadFn + '({', state); } } else if (attributes.length) { if (secondArg) { utils.append(', ', state); } utils.append('{', state); } var previousWasSpread = false; attributes.forEach(function(attr, index) { var isLast = (index === (attributes.length - 1)); if (attr.type === Syntax.JSXSpreadAttribute) { // close the previous or initial object if (!previousWasSpread) { utils.append('}, ', state); } // Move to the expression start, ignoring everything except parenthesis // and whitespace. utils.catchup(attr.range[0], state, stripNonParen); // Plus 1 to skip `{`. utils.move(attr.range[0] + 1, state); utils.catchup(attr.argument.range[0], state, stripNonParen); traverse(attr.argument, path, state); utils.catchup(attr.argument.range[1], state); // Move to the end, ignoring parenthesis and the closing `}` utils.catchup(attr.range[1] - 1, state, stripNonParen); if (!isLast) { utils.append(', ', state); } utils.move(attr.range[1], state); previousWasSpread = true; return; } // If the next attribute is a spread, we're effective last in this object if (!isLast) { isLast = attributes[index + 1].type === Syntax.JSXSpreadAttribute; } var name if (attr.name.namespace) { name = attr.name.namespace.name + ':' + attr.name.name.name } else { name = attr.name.name; } utils.catchup(attr.range[0], state, trimLeft); if (previousWasSpread) { utils.append('{', state); } utils.append(quoteJSObjKey(name) + ': ', state); if (attr.value) { utils.move(attr.name.range[1], state); utils.catchupNewlines(attr.value.range[0], state); if (attr.value.type === Syntax.Literal) { renderJSXLiteral(attr.value, isLast, state); } else { renderJSXExpressionContainer(traverse, attr.value, isLast, path, state); } } else { state.g.buffer += 'true'; state.g.position = attr.name.range[1]; if (!isLast) { utils.append(', ', state); } } utils.catchup(attr.range[1], state, trimLeft); previousWasSpread = false; }); if (!openingEl.selfClosing) { utils.catchup(openingEl.range[1] - 1, state, trimLeft); utils.move(openingEl.range[1], state); } if (attributes.length && !previousWasSpread) { utils.append('}', state); } if (hasAtLeastOneSpreadAttribute) { utils.append(')', state); } // filter out whitespace var children = object.children.filter(function(child) { return !(child.type === Syntax.Literal && typeof child.value === 'string' && child.value.match(/^[ \t]*[\r\n][ \t\r\n]*$/)); }); if (children.length) { if (!attributes.length) { if (secondArg) { utils.append(', ', state); } utils.append('null', state); } var lastRenderableIndex; children.forEach(function(child, index) { if (child.type !== Syntax.JSXExpressionContainer || child.expression.type !== Syntax.JSXEmptyExpression) { lastRenderableIndex = index; } }); if (lastRenderableIndex !== undefined) { utils.append(', ', state); } if (arrayChildren && children.length) { utils.append('[', state); } children.forEach(function(child, index) { utils.catchup(child.range[0], state, trimLeft); var isFirst = index === 0; var isLast = index >= lastRenderableIndex; if (child.type === Syntax.Literal) { renderJSXLiteral(child, isLast, state); } else if (child.type === Syntax.JSXExpressionContainer) { renderJSXExpressionContainer(traverse, child, isLast, path, state); } else { traverse(child, path, state); if (!isLast) { utils.append(',', state); } } utils.catchup(child.range[1], state, trimLeft); }); } if (openingEl.selfClosing) { // everything up to /> utils.catchup(openingEl.range[1] - 2, state, trimLeft); utils.move(openingEl.range[1], state); } else { // everything up to </close> utils.catchup(closingEl.range[0], state, trimLeft); utils.move(closingEl.range[1], state); } if (arrayChildren && children.length) { utils.append(']', state); } utils.append(')', state); return false; }
/** * Taken from {@link https://github.com/facebook/react/blob/0.10-stable/vendor/fbtransform/transforms/xjs.js} * * @param {Object} object * @param {Boolean} isLast * @param {Object} state * @param {Number} start * @param {Number} end * @private */ function renderJSXLiteral(object, isLast, state, start, end) { var lines = object.value.split(/\r\n|\n|\r/); if (start) { utils.append(start, state); } var lastNonEmptyLine = 0; lines.forEach(function (line, index) { if (line.match(/[^ \t]/)) { lastNonEmptyLine = index; } }); lines.forEach(function (line, index) { var isFirstLine = index === 0; var isLastLine = index === lines.length - 1; var isLastNonEmptyLine = index === lastNonEmptyLine; // replace rendered whitespace tabs with spaces var trimmedLine = line.replace(/\t/g, ' '); // trim whitespace touching a newline if (!isFirstLine) { trimmedLine = trimmedLine.replace(/^[ ]+/, ''); } if (!isLastLine) { trimmedLine = trimmedLine.replace(/[ ]+$/, ''); } if (!isFirstLine) { utils.append(line.match(/^[ \t]*/)[0], state); } if (trimmedLine || isLastNonEmptyLine) { utils.append( JSON.stringify(trimmedLine) + (!isLastNonEmptyLine ? " + ' ' +" : ''), state); if (isLastNonEmptyLine) { if (end) { utils.append(end, state); } if (!isLast) { utils.append(', ', state); } } // only restore tail whitespace if line had literals if (trimmedLine && !isLastLine) { utils.append(line.match(/[ \t]*$/)[0], state); } } if (!isLastLine) { utils.append('\n', state); } }); utils.move(object.range[1], state); }
function replaceEnv(node, state, value) { utils.catchup(node.range[0], state); utils.append(JSON.stringify(value), state); utils.move(node.range[1], state); }
function visitTypeAlias(traverse, node, path, state) { var ctx = new Context(state); utils.catchup(node.range[1], state); utils.append('var ' + node.id.name + ' = ' + ctx.getType(node.right) + ';', state); return false; }
attributes.forEach(function(attr, index) { var isLast = (index === (attributes.length - 1)); if (attr.type === Syntax.JSXSpreadAttribute) { // close the previous or initial object if (!previousWasSpread) { utils.append('}, ', state); } // Move to the expression start, ignoring everything except parenthesis // and whitespace. utils.catchup(attr.range[0], state, stripNonParen); // Plus 1 to skip `{`. utils.move(attr.range[0] + 1, state); utils.catchup(attr.argument.range[0], state, stripNonParen); traverse(attr.argument, path, state); utils.catchup(attr.argument.range[1], state); // Move to the end, ignoring parenthesis and the closing `}` utils.catchup(attr.range[1] - 1, state, stripNonParen); if (!isLast) { utils.append(', ', state); } utils.move(attr.range[1], state); previousWasSpread = true; return; } // If the next attribute is a spread, we're effective last in this object if (!isLast) { isLast = attributes[index + 1].type === Syntax.JSXSpreadAttribute; } var name if (attr.name.namespace) { name = attr.name.namespace.name + ':' + attr.name.name.name } else { name = attr.name.name; } utils.catchup(attr.range[0], state, trimLeft); if (previousWasSpread) { utils.append('{', state); } utils.append(quoteJSObjKey(name) + ': ', state); if (attr.value) { utils.move(attr.name.range[1], state); utils.catchupNewlines(attr.value.range[0], state); if (attr.value.type === Syntax.Literal) { renderJSXLiteral(attr.value, isLast, state); } else { renderJSXExpressionContainer(traverse, attr.value, isLast, path, state); } } else { state.g.buffer += 'true'; state.g.position = attr.name.range[1]; if (!isLast) { utils.append(', ', state); } } utils.catchup(attr.range[1], state, trimLeft); previousWasSpread = false; });