diff --git a/lib/coffeescript/lexer.js b/lib/coffeescript/lexer.js index 2a1c5f4094..70dfc2676c 100644 --- a/lib/coffeescript/lexer.js +++ b/lib/coffeescript/lexer.js @@ -52,6 +52,7 @@ this.importSpecifierList = false; // Used to identify when in an `IMPORT {...} FROM? ...`. this.exportSpecifierList = false; // Used to identify when in an `EXPORT {...} FROM? ...`. this.csxDepth = 0; // Used to optimize CSX checks, how deep in CSX we are. + this.csxObjAttribute = {}; // Used to detect if CSX attributes is wrapped in {} (
). this.chunkLine = opts.line || 0; // The start line for the current @chunk. this.chunkColumn = opts.column || 0; // The start column of the current @chunk. code = this.clean(code); // The stripped, cleaned original source code. @@ -730,8 +731,10 @@ // CSX is like JSX but for CoffeeScript. csxToken() { - var afterTag, colon, csxTag, end, firstChar, id, input, match, origin, prev, ref, token, tokens; + var afterTag, colon, csxTag, end, firstChar, id, input, match, origin, prev, prevChar, ref, token, tokens; firstChar = this.chunk[0]; + // Check the previous token to detect if attribute is spread. + prevChar = this.tokens.length > 0 ? this.tokens[this.tokens.length - 1][0] : ''; if (firstChar === '<') { match = CSX_IDENTIFIER.exec(this.chunk.slice(1)); // Not the right hand side of an unspaced comparison (i.e. `a', origin: origin, @@ -752,12 +755,18 @@ } else if (csxTag = this.atCSXTag()) { if (this.chunk.slice(0, 2) === '/>') { this.pair('/>'); - this.token('}', '}', 0, 2); + this.token(']', ']', 0, 2); this.token('CALL_END', ')', 0, 2); this.csxDepth--; return 2; } else if (firstChar === '{') { - token = this.token('(', '('); + if (prevChar === ':') { + token = this.token('(', '('); + this.csxObjAttribute[this.csxDepth] = false; + } else { + token = this.token('{', '{'); + this.csxObjAttribute[this.csxDepth] = true; + } this.ends.push({ tag: '}', origin: token @@ -766,7 +775,7 @@ } else if (firstChar === '>') { // Ignore terminators inside a tag. this.pair('/>'); // As if the current tag was self-closing. - origin = this.token('}', '}'); + origin = this.token(']', ']'); this.token(',', ','); ({ tokens, @@ -800,7 +809,12 @@ } else if (this.atCSXTag(1)) { if (firstChar === '}') { this.pair(firstChar); - this.token(')', ')'); + if (this.csxObjAttribute[this.csxDepth]) { + this.token('}', '}'); + this.csxObjAttribute[this.csxDepth] = false; + } else { + this.token(')', ')'); + } this.token(',', ','); return 1; } else { diff --git a/lib/coffeescript/nodes.js b/lib/coffeescript/nodes.js index 6280ef6395..66533d5a47 100644 --- a/lib/coffeescript/nodes.js +++ b/lib/coffeescript/nodes.js @@ -1670,7 +1670,7 @@ } compileCSX(o) { - var attributes, content, fragments, tag; + var attr, attrProps, attributes, content, fragments, j, len1, obj, ref1, tag; [attributes, content] = this.args; attributes.base.csx = true; if (content != null) { @@ -1678,7 +1678,23 @@ } fragments = [this.makeCode('<')]; fragments.push(...(tag = this.variable.compileToFragments(o, LEVEL_ACCESS))); - fragments.push(...attributes.compileToFragments(o, LEVEL_PAREN)); + if (attributes.base instanceof Arr) { + ref1 = attributes.base.objects; + for (j = 0, len1 = ref1.length; j < len1; j++) { + obj = ref1[j]; + attr = obj.base; + attrProps = (attr != null ? attr.properties : void 0) || []; + // Catch invalid CSX attributes:
+ if (!(attr instanceof Obj || attr instanceof IdentifierLiteral) || (attr instanceof Obj && !attr.generated && (attrProps.length > 1 || !(attrProps[0] instanceof Splat)))) { + obj.error("Unexpected token. Allowed CSX attributes are: id=\"val\", src={source}, {props...} or attribute."); + } + if (obj.base instanceof Obj) { + obj.base.csx = true; + } + fragments.push(this.makeCode(' ')); + fragments.push(...obj.compileToFragments(o, LEVEL_PAREN)); + } + } if (content) { fragments.push(this.makeCode('>')); fragments.push(...content.compileNode(o, LEVEL_LIST)); @@ -2109,12 +2125,16 @@ } } } - if (this.hasSplat()) { + if (this.hasSplat() && !this.csx) { // Object spread properties. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md return this.compileSpread(o); } idt = o.indent += TAB; lastNode = this.lastNode(this.properties); + if (this.csx) { + // CSX attributes
+ return this.compileCSXAttributes(o); + } // If this object is the left-hand side of an assignment, all its children // are too. if (this.lhs) { @@ -2136,7 +2156,7 @@ ref1 = this.properties; for (l = 0, len3 = ref1.length; l < len3; l++) { prop = ref1[l]; - if (prop instanceof Assign && prop.context === 'object' && !this.csx) { + if (prop instanceof Assign && prop.context === 'object') { isCompact = false; } } @@ -2144,7 +2164,7 @@ answer.push(this.makeCode(isCompact ? '' : '\n')); for (i = q = 0, len4 = props.length; q < len4; i = ++q) { prop = props[i]; - join = i === props.length - 1 ? '' : isCompact && this.csx ? ' ' : isCompact ? ', ' : prop === lastNode || this.csx ? '\n' : ',\n'; + join = i === props.length - 1 ? '' : isCompact ? ', ' : prop === lastNode ? '\n' : ',\n'; indent = isCompact ? '' : idt; key = prop instanceof Assign && prop.context === 'object' ? prop.variable : prop instanceof Assign ? (!this.lhs ? prop.operatorToken.error(`unexpected ${prop.operatorToken.value}`) : void 0, prop.variable) : prop; if (key instanceof Value && key.hasProperties()) { @@ -2168,21 +2188,13 @@ if (indent) { answer.push(this.makeCode(indent)); } - if (this.csx) { - prop.csx = true; - } - if (this.csx && i === 0) { - answer.push(this.makeCode(' ')); - } answer.push(...prop.compileToFragments(o, LEVEL_TOP)); if (join) { answer.push(this.makeCode(join)); } } answer.push(this.makeCode(isCompact ? '' : `\n${this.tab}`)); - if (!this.csx) { - answer = this.wrapInBraces(answer); - } + answer = this.wrapInBraces(answer); if (this.front) { return this.wrapInParentheses(answer); } else { @@ -2256,6 +2268,27 @@ return (new Call(new Literal('Object.assign'), slices)).compileToFragments(o); } + compileCSXAttributes(o) { + var answer, i, j, join, len1, prop, props; + props = this.properties; + answer = []; + for (i = j = 0, len1 = props.length; j < len1; i = ++j) { + prop = props[i]; + prop.csx = true; + join = i === props.length - 1 ? '' : ' '; + if (prop instanceof Splat) { + prop = new Literal(`{${prop.compile(o)}}`); + } + answer.push(...prop.compileToFragments(o, LEVEL_TOP)); + answer.push(this.makeCode(join)); + } + if (this.front) { + return this.wrapInParentheses(answer); + } else { + return answer; + } + } + }; Obj.prototype.children = ['properties']; diff --git a/lib/coffeescript/parser.js b/lib/coffeescript/parser.js index 198d11a055..22ca21d91f 100755 --- a/lib/coffeescript/parser.js +++ b/lib/coffeescript/parser.js @@ -105,16 +105,13 @@ case 12: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.StatementLiteral($$[$0])); break; case 27: -this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Op($$[$0], - new yy.Value(new yy.Literal('')))); +this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Op($$[$0], new yy.Value(new yy.Literal('')))); break; case 28: case 271: case 272: case 275: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op($$[$0-1], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op($$[$0-1], $$[$0])); break; case 29: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op($$[$0-2].concat($$[$0-1]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op($$[$0-2].concat($$[$0-1]), $$[$0])); break; case 30: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Block); @@ -165,49 +162,34 @@ case 48: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.NaNLiteral($$[$0])); break; case 49: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign($$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign($$[$0-2], $$[$0])); break; case 50: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Assign($$[$0-3], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Assign($$[$0-3], $$[$0])); break; case 51: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign($$[$0-4], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign($$[$0-4], $$[$0-1])); break; case 52: case 108: case 112: case 113: case 115: case 116: case 117: case 118: case 120: case 244: case 245: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Value($$[$0])); break; case 54: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-2])(new yy.Value($$[$0-2])), - $$[$0], - 'object', - { +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-2])(new yy.Value($$[$0-2])), $$[$0], 'object', { operatorToken: yy.addDataToNode(yy, _$[$0-1])(new yy.Literal($$[$0-1])) })); break; case 55: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-4])(new yy.Value($$[$0-4])), - $$[$0-1], - 'object', - { +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-4])(new yy.Value($$[$0-4])), $$[$0-1], 'object', { operatorToken: yy.addDataToNode(yy, _$[$0-3])(new yy.Literal($$[$0-3])) })); break; case 56: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-2])(new yy.Value($$[$0-2])), - $$[$0], - null, - { +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-2])(new yy.Value($$[$0-2])), $$[$0], null, { operatorToken: yy.addDataToNode(yy, _$[$0-1])(new yy.Literal($$[$0-1])) })); break; case 57: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-4])(new yy.Value($$[$0-4])), - $$[$0-1], - null, - { +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign(yy.addDataToNode(yy, _$[$0-4])(new yy.Value($$[$0-4])), $$[$0-1], null, { operatorToken: yy.addDataToNode(yy, _$[$0-3])(new yy.Literal($$[$0-3])) })); break; @@ -224,18 +206,13 @@ case 66: case 107: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Splat($$[$0])); break; case 72: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.SuperCall(yy.addDataToNode(yy, _$[$0-1])(new yy.Super), - $$[$0], - false, - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.SuperCall(yy.addDataToNode(yy, _$[$0-1])(new yy.Super), $$[$0], false, $$[$0-1])); break; case 73: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Call(new yy.Value($$[$0-1]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Call(new yy.Value($$[$0-1]), $$[$0])); break; case 74: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Call($$[$0-1], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Call($$[$0-1], $$[$0])); break; case 75: case 76: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])((new yy.Value($$[$0-1])).add($$[$0])); @@ -265,14 +242,10 @@ case 85: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.AwaitReturn); break; case 86: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Code($$[$0-3], - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Code($$[$0-3], $$[$0], $$[$0-1])); break; case 87: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Code([], - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Code([], $$[$0], $$[$0-1])); break; case 88: case 89: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.FuncGlyph($$[$0])); @@ -296,18 +269,13 @@ case 97: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Param($$[$0])); break; case 98: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Param($$[$0-1], - null, - true)); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Param($$[$0-1], null, true)); break; case 99: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Param($$[$0], - null, - true)); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Param($$[$0], null, true)); break; case 100: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Param($$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Param($$[$0-2], $$[$0])); break; case 101: case 210: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Expansion); @@ -316,36 +284,25 @@ case 109: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])($$[$0-1].add($$[$0])); break; case 121: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Super(yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0])), - [], - false, - $$[$0-2])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Super(yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0])), [], false, $$[$0-2])); break; case 122: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Super(yy.addDataToNode(yy, _$[$0-1])(new yy.Index($$[$0-1])), - [], - false, - $$[$0-3])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Super(yy.addDataToNode(yy, _$[$0-1])(new yy.Index($$[$0-1])), [], false, $$[$0-3])); break; case 124: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Access($$[$0], - 'soak')); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Access($$[$0], 'soak')); break; case 125: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'))), - yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))]); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'))), yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))]); break; case 126: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'), - 'soak')), - yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))]); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Access(new yy.PropertyName('prototype'), 'soak')), yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))]); break; case 127: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Access(new yy.PropertyName('prototype'))); break; case 130: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(yy.extend($$[$0], - { +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(yy.extend($$[$0], { soak: true })); break; @@ -356,76 +313,52 @@ case 132: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Slice($$[$0])); break; case 133: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Obj($$[$0-2], - $$[$0-3].generated)); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Obj($$[$0-2], $$[$0-3].generated)); break; case 139: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Class); break; case 140: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Class(null, - null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Class(null, null, $$[$0])); break; case 141: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Class(null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Class(null, $$[$0])); break; case 142: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Class(null, - $$[$0-1], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Class(null, $$[$0-1], $$[$0])); break; case 143: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Class($$[$0])); break; case 144: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Class($$[$0-1], - null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Class($$[$0-1], null, $$[$0])); break; case 145: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Class($$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Class($$[$0-2], $$[$0])); break; case 146: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Class($$[$0-3], - $$[$0-1], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Class($$[$0-3], $$[$0-1], $$[$0])); break; case 147: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.ImportDeclaration(null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.ImportDeclaration(null, $$[$0])); break; case 148: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-2], - null), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-2], null), $$[$0])); break; case 149: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, - $$[$0-2]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, $$[$0-2]), $$[$0])); break; case 150: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, - new yy.ImportSpecifierList([])), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, new yy.ImportSpecifierList([])), $$[$0])); break; case 151: -this.$ = yy.addDataToNode(yy, _$[$0-6], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, - new yy.ImportSpecifierList($$[$0-4])), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-6], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause(null, new yy.ImportSpecifierList($$[$0-4])), $$[$0])); break; case 152: -this.$ = yy.addDataToNode(yy, _$[$0-5], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-4], - $$[$0-2]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-5], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-4], $$[$0-2]), $$[$0])); break; case 153: -this.$ = yy.addDataToNode(yy, _$[$0-8], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-7], - new yy.ImportSpecifierList($$[$0-4])), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-8], _$[$0])(new yy.ImportDeclaration(new yy.ImportClause($$[$0-7], new yy.ImportSpecifierList($$[$0-4])), $$[$0])); break; case 157: case 177: case 190: case 206: this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])($$[$0-2]); @@ -434,22 +367,19 @@ case 159: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.ImportSpecifier($$[$0])); break; case 160: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ImportSpecifier($$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ImportSpecifier($$[$0-2], $$[$0])); break; case 161: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.ImportSpecifier(new yy.Literal($$[$0]))); break; case 162: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ImportSpecifier(new yy.Literal($$[$0-2]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ImportSpecifier(new yy.Literal($$[$0-2]), $$[$0])); break; case 163: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.ImportDefaultSpecifier($$[$0])); break; case 164: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ImportNamespaceSpecifier(new yy.Literal($$[$0-2]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ImportNamespaceSpecifier(new yy.Literal($$[$0-2]), $$[$0])); break; case 165: this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportNamedDeclaration(new yy.ExportSpecifierList([]))); @@ -461,26 +391,17 @@ case 167: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.ExportNamedDeclaration($$[$0])); break; case 168: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-2], - $$[$0], - null, - { +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-2], $$[$0], null, { moduleDeclaration: 'export' }))); break; case 169: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-3], - $$[$0], - null, - { +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-3], $$[$0], null, { moduleDeclaration: 'export' }))); break; case 170: -this.$ = yy.addDataToNode(yy, _$[$0-5], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-4], - $$[$0-1], - null, - { +this.$ = yy.addDataToNode(yy, _$[$0-5], _$[$0])(new yy.ExportNamedDeclaration(new yy.Assign($$[$0-4], $$[$0-1], null, { moduleDeclaration: 'export' }))); break; @@ -488,46 +409,34 @@ case 171: this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportDefaultDeclaration($$[$0])); break; case 172: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ExportAllDeclaration(new yy.Literal($$[$0-2]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.ExportAllDeclaration(new yy.Literal($$[$0-2]), $$[$0])); break; case 173: -this.$ = yy.addDataToNode(yy, _$[$0-6], _$[$0])(new yy.ExportNamedDeclaration(new yy.ExportSpecifierList($$[$0-4]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-6], _$[$0])(new yy.ExportNamedDeclaration(new yy.ExportSpecifierList($$[$0-4]), $$[$0])); break; case 179: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.ExportSpecifier($$[$0])); break; case 180: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportSpecifier($$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportSpecifier($$[$0-2], $$[$0])); break; case 181: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportSpecifier($$[$0-2], - new yy.Literal($$[$0]))); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportSpecifier($$[$0-2], new yy.Literal($$[$0]))); break; case 182: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.ExportSpecifier(new yy.Literal($$[$0]))); break; case 183: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportSpecifier(new yy.Literal($$[$0-2]), - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.ExportSpecifier(new yy.Literal($$[$0-2]), $$[$0])); break; case 184: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.TaggedTemplateCall($$[$0-2], - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.TaggedTemplateCall($$[$0-2], $$[$0], $$[$0-1])); break; case 185: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Call($$[$0-2], - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Call($$[$0-2], $$[$0], $$[$0-1])); break; case 186: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.SuperCall(yy.addDataToNode(yy, _$[$0-2])(new yy.Super), - $$[$0], - $$[$0-1], - $$[$0-2])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.SuperCall(yy.addDataToNode(yy, _$[$0-2])(new yy.Super), $$[$0], $$[$0-1], $$[$0-2])); break; case 187: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(false); @@ -542,9 +451,7 @@ case 191: case 192: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Value(new yy.ThisLiteral($$[$0]))); break; case 193: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Value(yy.addDataToNode(yy, _$[$0-1])(new yy.ThisLiteral($$[$0-1])), - [yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))], - 'this')); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Value(yy.addDataToNode(yy, _$[$0-1])(new yy.ThisLiteral($$[$0-1])), [yy.addDataToNode(yy, _$[$0])(new yy.Access($$[$0]))], 'this')); break; case 194: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Arr([])); @@ -559,65 +466,43 @@ case 197: this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])('exclusive'); break; case 198: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Range($$[$0-3], - $$[$0-1], - $$[$0-2])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Range($$[$0-3], $$[$0-1], $$[$0-2])); break; case 199: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Range($$[$0-2], - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Range($$[$0-2], $$[$0], $$[$0-1])); break; case 200: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Range($$[$0-1], - null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Range($$[$0-1], null, $$[$0])); break; case 201: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Range(null, - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Range(null, $$[$0], $$[$0-1])); break; case 202: -this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Range(null, - null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0], _$[$0])(new yy.Range(null, null, $$[$0])); break; case 212: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([].concat($$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([].concat($$[$0-2], $$[$0])); break; case 213: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Try($$[$0])); break; case 214: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Try($$[$0-1], - $$[$0][0], - $$[$0][1])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Try($$[$0-1], $$[$0][0], $$[$0][1])); break; case 215: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Try($$[$0-2], - null, - null, - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Try($$[$0-2], null, null, $$[$0])); break; case 216: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Try($$[$0-3], - $$[$0-2][0], - $$[$0-2][1], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Try($$[$0-3], $$[$0-2][0], $$[$0-2][1], $$[$0])); break; case 217: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([$$[$0-1], - $$[$0]]); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([$$[$0-1], $$[$0]]); break; case 218: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Value($$[$0-1])), - $$[$0]]); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([yy.addDataToNode(yy, _$[$0-1])(new yy.Value($$[$0-1])), $$[$0]]); break; case 219: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([null, - $$[$0]]); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])([null, $$[$0]]); break; case 220: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Throw($$[$0])); @@ -635,20 +520,17 @@ case 224: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.While($$[$0])); break; case 225: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.While($$[$0-2], - { +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.While($$[$0-2], { guard: $$[$0] })); break; case 226: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.While($$[$0], - { +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.While($$[$0], { invert: true })); break; case 227: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.While($$[$0-2], - { +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.While($$[$0-2], { invert: true, guard: $$[$0] })); @@ -669,12 +551,10 @@ case 233: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.While(yy.addDataToNode(yy, _$[$0-1])(new yy.BooleanLiteral('true'))).addBody(yy.addDataToNode(yy, _$[$0])(yy.Block.wrap([$$[$0]])))); break; case 234: case 235: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.For($$[$0-1], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.For($$[$0-1], $$[$0])); break; case 236: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.For($$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.For($$[$0], $$[$0-1])); break; case 237: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])({ @@ -707,8 +587,7 @@ this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])((function () { }())); break; case 247: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([$$[$0-2], - $$[$0]]); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([$$[$0-2], $$[$0]]); break; case 248: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])({ @@ -768,45 +647,33 @@ this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])({ }); break; case 257: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Switch($$[$0-3], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Switch($$[$0-3], $$[$0-1])); break; case 258: -this.$ = yy.addDataToNode(yy, _$[$0-6], _$[$0])(new yy.Switch($$[$0-5], - $$[$0-3], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-6], _$[$0])(new yy.Switch($$[$0-5], $$[$0-3], $$[$0-1])); break; case 259: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Switch(null, - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Switch(null, $$[$0-1])); break; case 260: -this.$ = yy.addDataToNode(yy, _$[$0-5], _$[$0])(new yy.Switch(null, - $$[$0-3], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-5], _$[$0])(new yy.Switch(null, $$[$0-3], $$[$0-1])); break; case 262: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])($$[$0-1].concat($$[$0])); break; case 263: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([[$$[$0-1], - $$[$0]]]); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])([[$$[$0-1], $$[$0]]]); break; case 264: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])([[$$[$0-2], - $$[$0-1]]]); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])([[$$[$0-2], $$[$0-1]]]); break; case 265: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.If($$[$0-1], - $$[$0], - { +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.If($$[$0-1], $$[$0], { type: $$[$0-2] })); break; case 266: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])($$[$0-4].addElse(yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.If($$[$0-1], - $$[$0], - { +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])($$[$0-4].addElse(yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.If($$[$0-1], $$[$0], { type: $$[$0-2] })))); break; @@ -814,86 +681,58 @@ case 268: this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])($$[$0-2].addElse($$[$0])); break; case 269: case 270: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.If($$[$0], - yy.addDataToNode(yy, _$[$0-2])(yy.Block.wrap([$$[$0-2]])), - { +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.If($$[$0], yy.addDataToNode(yy, _$[$0-2])(yy.Block.wrap([$$[$0-2]])), { type: $$[$0-1], statement: true })); break; case 273: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('-', - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('-', $$[$0])); break; case 274: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('+', - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('+', $$[$0])); break; case 276: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('--', - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('--', $$[$0])); break; case 277: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('++', - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('++', $$[$0])); break; case 278: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('--', - $$[$0-1], - null, - true)); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('--', $$[$0-1], null, true)); break; case 279: -this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('++', - $$[$0-1], - null, - true)); +this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Op('++', $$[$0-1], null, true)); break; case 280: this.$ = yy.addDataToNode(yy, _$[$0-1], _$[$0])(new yy.Existence($$[$0-1])); break; case 281: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op('+', - $$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op('+', $$[$0-2], $$[$0])); break; case 282: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op('-', - $$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op('-', $$[$0-2], $$[$0])); break; case 283: case 284: case 285: case 286: case 287: case 288: case 289: case 290: case 291: case 292: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op($$[$0-1], - $$[$0-2], - $$[$0])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Op($$[$0-1], $$[$0-2], $$[$0])); break; case 293: this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])((function () { if ($$[$0-1].charAt(0) === '!') { - return new yy.Op($$[$0-1].slice(1), - $$[$0-2], - $$[$0]).invert(); + return new yy.Op($$[$0-1].slice(1), $$[$0-2], $$[$0]).invert(); } else { - return new yy.Op($$[$0-1], - $$[$0-2], - $$[$0]); + return new yy.Op($$[$0-1], $$[$0-2], $$[$0]); } }())); break; case 294: -this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign($$[$0-2], - $$[$0], - $$[$0-1])); +this.$ = yy.addDataToNode(yy, _$[$0-2], _$[$0])(new yy.Assign($$[$0-2], $$[$0], $$[$0-1])); break; case 295: -this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign($$[$0-4], - $$[$0-1], - $$[$0-3])); +this.$ = yy.addDataToNode(yy, _$[$0-4], _$[$0])(new yy.Assign($$[$0-4], $$[$0-1], $$[$0-3])); break; case 296: -this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Assign($$[$0-3], - $$[$0], - $$[$0-2])); +this.$ = yy.addDataToNode(yy, _$[$0-3], _$[$0])(new yy.Assign($$[$0-3], $$[$0], $$[$0-2])); break; } }, diff --git a/src/lexer.coffee b/src/lexer.coffee index b1a3f78eb6..f0230b1ee5 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -49,6 +49,7 @@ exports.Lexer = class Lexer @importSpecifierList = no # Used to identify when in an `IMPORT {...} FROM? ...`. @exportSpecifierList = no # Used to identify when in an `EXPORT {...} FROM? ...`. @csxDepth = 0 # Used to optimize CSX checks, how deep in CSX we are. + @csxObjAttribute = {} # Used to detect if CSX attributes is wrapped in {} (
). @chunkLine = opts.line or 0 # The start line for the current @chunk. @@ -546,6 +547,8 @@ exports.Lexer = class Lexer # CSX is like JSX but for CoffeeScript. csxToken: -> firstChar = @chunk[0] + # Check the previous token to detect if attribute is spread. + prevChar = if @tokens.length > 0 then @tokens[@tokens.length - 1][0] else '' if firstChar is '<' match = CSX_IDENTIFIER.exec @chunk[1...] return 0 unless match and ( @@ -558,25 +561,30 @@ exports.Lexer = class Lexer [input, id, colon] = match origin = @token 'CSX_TAG', id, 1, id.length @token 'CALL_START', '(' - @token '{', '{' + @token '[', '[' @ends.push tag: '/>', origin: origin, name: id @csxDepth++ return id.length + 1 else if csxTag = @atCSXTag() if @chunk[...2] is '/>' @pair '/>' - @token '}', '}', 0, 2 + @token ']', ']', 0, 2 @token 'CALL_END', ')', 0, 2 @csxDepth-- return 2 else if firstChar is '{' - token = @token '(', '(' + if prevChar is ':' + token = @token '(', '(' + @csxObjAttribute[@csxDepth] = no + else + token = @token '{', '{' + @csxObjAttribute[@csxDepth] = yes @ends.push {tag: '}', origin: token} return 1 else if firstChar is '>' # Ignore terminators inside a tag. @pair '/>' # As if the current tag was self-closing. - origin = @token '}', '}' + origin = @token ']', ']' @token ',', ',' {tokens, index: end} = @matchWithInterpolations INSIDE_CSX, '>', ' + if not (attr instanceof Obj or attr instanceof IdentifierLiteral) or (attr instanceof Obj and not attr.generated and (attrProps.length > 1 or not (attrProps[0] instanceof Splat))) + obj.error """ + Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. + """ + obj.base.csx = yes if obj.base instanceof Obj + fragments.push @makeCode ' ' + fragments.push obj.compileToFragments(o, LEVEL_PAREN)... if content fragments.push @makeCode('>') fragments.push content.compileNode(o, LEVEL_LIST)... @@ -1425,11 +1436,14 @@ exports.Obj = class Obj extends Base node.error 'cannot have an implicit value in an implicit object' # Object spread properties. https://github.com/tc39/proposal-object-rest-spread/blob/master/Spread.md - return @compileSpread o if @hasSplat() + return @compileSpread o if @hasSplat() and not @csx idt = o.indent += TAB lastNode = @lastNode @properties + # CSX attributes
+ return @compileCSXAttributes o if @csx + # If this object is the left-hand side of an assignment, all its children # are too. if @lhs @@ -1443,7 +1457,7 @@ exports.Obj = class Obj extends Base isCompact = yes for prop in @properties - if prop instanceof Assign and prop.context is 'object' and not @csx + if prop instanceof Assign and prop.context is 'object' isCompact = no answer = [] @@ -1451,11 +1465,9 @@ exports.Obj = class Obj extends Base for prop, i in props join = if i is props.length - 1 '' - else if isCompact and @csx - ' ' else if isCompact ', ' - else if prop is lastNode or @csx + else if prop is lastNode '\n' else ',\n' @@ -1480,12 +1492,10 @@ exports.Obj = class Obj extends Base else if not prop.bareLiteral?(IdentifierLiteral) prop = new Assign prop, prop, 'object' if indent then answer.push @makeCode indent - prop.csx = yes if @csx - answer.push @makeCode ' ' if @csx and i is 0 answer.push prop.compileToFragments(o, LEVEL_TOP)... if join then answer.push @makeCode join answer.push @makeCode if isCompact then '' else "\n#{@tab}" - answer = @wrapInBraces answer if not @csx + answer = @wrapInBraces answer if @front then @wrapInParentheses answer else answer assigns: (name) -> @@ -1521,6 +1531,17 @@ exports.Obj = class Obj extends Base slices.unshift new Obj unless slices[0] instanceof Obj (new Call new Literal('Object.assign'), slices).compileToFragments o + compileCSXAttributes: (o) -> + props = @properties + answer = [] + for prop, i in props + prop.csx = yes + join = if i is props.length - 1 then '' else ' ' + prop = new Literal "{#{prop.compile(o)}}" if prop instanceof Splat + answer.push prop.compileToFragments(o, LEVEL_TOP)... + answer.push @makeCode join + if @front then @wrapInParentheses answer else answer + #### Arr # An array literal. diff --git a/test/csx.coffee b/test/csx.coffee index ca407a9be3..61ede9cd8c 100644 --- a/test/csx.coffee +++ b/test/csx.coffee @@ -483,147 +483,115 @@ test 'self closing tag with namespace', -> ; ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'self closing tag with spread attribute', -> -# eqJS ''' -# -# ''', ''' -# React.createElement(Component, Object.assign({"a": (b)}, x , {"b": "c"})) -# ''' - -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'complex spread attribute', -> -# eqJS ''' -# -# ''', ''' -# React.createElement(Component, Object.assign({}, x, {"a": (b)}, x , {"b": "c"}, $my_xtraCoolVar123 )) -# ''' - -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'multiline spread attribute', -> -# eqJS ''' -# -# -# ''', ''' -# React.createElement(Component, Object.assign({}, -# x , {"a": (b)}, x , {"b": "c"}, z ) -# ) -# ''' +test 'self closing tag with spread attribute', -> + eqJS ''' + + ''', ''' + ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'multiline tag with spread attribute', -> -# eqJS ''' -# -# -# ''', ''' -# React.createElement(Component, Object.assign({ \ -# "z": "1" -# }, x, { \ -# "a": (b), \ -# "b": "c" -# }) -# ) -# ''' +test 'complex spread attribute', -> + eqJS ''' + + ''', ''' + ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'multiline tag with spread attribute first', -> -# eqJS ''' -# -# -# ''', ''' -# React.createElement(Component, Object.assign({}, \ - -# x, { \ -# "z": "1", \ -# "a": (b), \ -# "b": "c" -# }) -# ) -# ''' +test 'multiline spread attribute', -> + eqJS ''' + + + ''', ''' + + ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'complex multiline spread attribute', -> -# eqJS ''' -# -#
-# -# ''', ''' -# React.createElement(Component, Object.assign({}, \ +test 'multiline tag with spread attribute', -> + eqJS ''' + + + ''', ''' + + ; + ''' -# y, {"a": (b)}, x , {"b": "c"}, z ), -# React.createElement("div", {"code": (someFunc({a:{b:{}, C:'}'}}))}) -# ) -# ''' +test 'multiline tag with spread attribute first', -> + eqJS ''' + + + ''', ''' + + ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'self closing spread attribute on single line', -> -# eqJS ''' -# -# ''', ''' -# React.createElement(Component, Object.assign({"a": "b", "c": "d"}, @props )) -# ''' +test 'complex multiline spread attribute', -> + eqJS ''' + +
+ + ''', ''' + +
+ ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'self closing spread attribute on new line', -> -# eqJS ''' -# -# ''', ''' -# React.createElement(Component, Object.assign({ \ -# "a": "b", \ -# "c": "d" -# }, @props -# )) -# ''' +test 'self closing spread attribute on single line', -> + eqJS ''' + + ''', ''' + ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'self closing spread attribute on same line', -> -# eqJS ''' -# -# ''', ''' -# React.createElement(Component, Object.assign({ \ -# "a": "b", \ -# "c": "d" -# }, @props )) -# ''' +test 'self closing spread attribute on new line', -> + eqJS ''' + + ''', ''' + ; + ''' -# TODO: Uncomment the following test once destructured object spreads are supported. -# test 'self closing spread attribute on next line', -> -# eqJS ''' -# + eqJS ''' + + ''', ''' + ; + ''' -# /> -# ''', ''' -# React.createElement(Component, Object.assign({ \ -# "a": "b", \ -# "c": "d" -# }, @props +test 'self closing spread attribute on next line', -> + eqJS ''' + + ''', ''' + ; + ''' test 'empty strings are not converted to true', -> eqJS ''' diff --git a/test/error_messages.coffee b/test/error_messages.coffee index fe6f3559ac..3aa7241c9b 100644 --- a/test/error_messages.coffee +++ b/test/error_messages.coffee @@ -1587,6 +1587,50 @@ test "CSX error: ambiguous tag-like expression", -> ^ ''' +test 'CSX error: invalid attributes', -> + assertErrorFormat ''' +
+ ''', ''' + [stdin]:1:12: error: Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. +
+ ^^^^^^^ + ''' + assertErrorFormat ''' +
+ ''', ''' + [stdin]:1:12: error: Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. +
+ ^^^^^^^ + ''' + assertErrorFormat ''' +
+ ''', ''' + [stdin]:1:6: error: Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. +
+ ^^^^^^^^ + ''' + assertErrorFormat ''' +
+ ''', ''' + [stdin]:1:11: error: Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. +
+ ^^^ + ''' + assertErrorFormat ''' +
+ ''', ''' + [stdin]:1:6: error: Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. +
+ ^^^^^^^^^^^^^^^^^^^^^^^^ + ''' + assertErrorFormat ''' +
+ ''', ''' + [stdin]:1:6: error: Unexpected token. Allowed CSX attributes are: id="val", src={source}, {props...} or attribute. +
+ ^^^^^^^^^^^^^^^^ + ''' + test 'Bound method called as callback before binding throws runtime error', -> class Base constructor: ->