coffeehaml 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/parser.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
2
  // parser.coffee — recursive descent parser
3
3
  // Converts token stream into AST
4
- var ParserState, findColon, isElse, parseAttributeBlock, parseBlock, parseComment, parseControlFlow, parseControlKind, parseDoctype, parseElement, parseFilter, parseHtmlComment, parseImplicitDiv, parseNode, parseOutput, parseText, splitAttributePairs, stripControlKeyword;
4
+ var ParserState, cleanAttrName, findColon, findEquals, isElse, parseAttributeBlock, parseBareAttributes, parseBlock, parseComment, parseControlFlow, parseControlKind, parseDoctype, parseElement, parseFilter, parseHtmlComment, parseImplicitDiv, parseNode, parseOutput, parseText, splitAttributePairs, splitBareAttributePairs, stripControlKeyword;
5
5
 
6
6
  import {
7
7
  TokenType
@@ -202,7 +202,7 @@ parseElement = function(state) {
202
202
  attributes = [];
203
203
  isSelfClosing = false;
204
204
  attrStyle = null;
205
- while (state.current() && ((ref1 = state.current().type) === TokenType.CLASS || ref1 === TokenType.ID || ref1 === TokenType.ATTRS_BRACE || ref1 === TokenType.ATTRS_PAREN || ref1 === TokenType.SELF_CLOSE)) {
205
+ while (state.current() && ((ref1 = state.current().type) === TokenType.CLASS || ref1 === TokenType.ID || ref1 === TokenType.ATTRS_BRACE || ref1 === TokenType.ATTRS_PAREN || ref1 === TokenType.ATTRS_BARE || ref1 === TokenType.SELF_CLOSE)) {
206
206
  tok = state.current();
207
207
  switch (tok.type) {
208
208
  case TokenType.CLASS:
@@ -223,6 +223,11 @@ parseElement = function(state) {
223
223
  attributes.push(...parseAttributeBlock(tok.value, '()', tagToken.location));
224
224
  attrStyle = 'parens';
225
225
  break;
226
+ case TokenType.ATTRS_BARE:
227
+ state.advance();
228
+ attributes.push(...parseBareAttributes(tok.value));
229
+ attrStyle = 'bare';
230
+ break;
226
231
  case TokenType.SELF_CLOSE:
227
232
  state.advance();
228
233
  isSelfClosing = true;
@@ -271,7 +276,7 @@ parseImplicitDiv = function(state) {
271
276
  attributes = [];
272
277
  attrStyle = null;
273
278
  firstToken = state.current();
274
- while (state.current() && ((ref = state.current().type) === TokenType.CLASS || ref === TokenType.ID || ref === TokenType.ATTRS_BRACE || ref === TokenType.ATTRS_PAREN)) {
279
+ while (state.current() && ((ref = state.current().type) === TokenType.CLASS || ref === TokenType.ID || ref === TokenType.ATTRS_BRACE || ref === TokenType.ATTRS_PAREN || ref === TokenType.ATTRS_BARE)) {
275
280
  tok = state.current();
276
281
  switch (tok.type) {
277
282
  case TokenType.CLASS:
@@ -291,6 +296,11 @@ parseImplicitDiv = function(state) {
291
296
  state.advance();
292
297
  attributes.push(...parseAttributeBlock(tok.value, '()', firstToken.location));
293
298
  attrStyle = 'parens';
299
+ break;
300
+ case TokenType.ATTRS_BARE:
301
+ state.advance();
302
+ attributes.push(...parseBareAttributes(tok.value));
303
+ attrStyle = 'bare';
294
304
  }
295
305
  }
296
306
  // Parse inline text
@@ -472,6 +482,110 @@ parseText = function(state) {
472
482
  };
473
483
 
474
484
  // ─── Attribute Block Parser ────────────────────────────────
485
+
486
+ // Parse bare HTML-style attributes: key="val", key='val', key={expr}, flag
487
+ parseBareAttributes = function(source) {
488
+ var attrs, eqIdx, j, len, name, part, parts, trimmed, val;
489
+ attrs = [];
490
+ if (!(source != null ? source.trim() : void 0)) {
491
+ return attrs;
492
+ }
493
+ // Split on whitespace respecting quotes and braces
494
+ parts = splitBareAttributePairs(source);
495
+ for (j = 0, len = parts.length; j < len; j++) {
496
+ part = parts[j];
497
+ trimmed = part.trim();
498
+ if (!trimmed) {
499
+ continue;
500
+ }
501
+ // key=value
502
+ eqIdx = findEquals(trimmed);
503
+ if (eqIdx > 0) {
504
+ name = trimmed.slice(0, eqIdx);
505
+ val = trimmed.slice(eqIdx + 1);
506
+ attrs.push(new Attribute(cleanAttrName(name), new Expression(val), false));
507
+ } else {
508
+ // Bare word → shorthand attribute like `flag` → flag={flag}
509
+ attrs.push(new Attribute(trimmed, new Expression(trimmed), true));
510
+ }
511
+ }
512
+ return attrs;
513
+ };
514
+
515
+ // Split bare attributes on whitespace, respecting quotes and braces
516
+ splitBareAttributePairs = function(source) {
517
+ var ch, depth, i, q, result, start;
518
+ result = [];
519
+ depth = 0;
520
+ start = 0;
521
+ i = 0;
522
+ while (i < source.length) {
523
+ ch = source[i];
524
+ if (ch === '{' || ch === '[' || ch === '(') {
525
+ depth++;
526
+ } else if (ch === '}' || ch === ']' || ch === ')') {
527
+ depth--;
528
+ } else if ((ch === '"' || ch === "'") && depth === 0) {
529
+ q = ch;
530
+ i++;
531
+ while (i < source.length && source[i] !== q) {
532
+ if (source[i] === '\\') {
533
+ i++;
534
+ }
535
+ i++;
536
+ }
537
+ } else if (/[\t ]/.test(ch) && depth === 0) {
538
+ if (i > start) {
539
+ result.push(source.slice(start, i));
540
+ }
541
+ start = i + 1;
542
+ }
543
+ i++;
544
+ }
545
+ if (i > start) {
546
+ result.push(source.slice(start));
547
+ }
548
+ return result;
549
+ };
550
+
551
+ // Find = sign (not inside quotes/braces)
552
+ findEquals = function(source) {
553
+ var ch, depth, i, q;
554
+ depth = 0;
555
+ i = 0;
556
+ while (i < source.length) {
557
+ ch = source[i];
558
+ if (ch === '{' || ch === '[' || ch === '(') {
559
+ depth++;
560
+ } else if (ch === '}' || ch === ']' || ch === ')') {
561
+ depth--;
562
+ } else if ((ch === '"' || ch === "'") && depth === 0) {
563
+ q = ch;
564
+ i++;
565
+ while (i < source.length && source[i] !== q) {
566
+ if (source[i] === '\\') {
567
+ i++;
568
+ }
569
+ i++;
570
+ }
571
+ } else if (ch === '=' && depth === 0) {
572
+ return i;
573
+ }
574
+ i++;
575
+ }
576
+ return -1;
577
+ };
578
+
579
+ // Remove surrounding quotes from attr name
580
+ cleanAttrName = function(name) {
581
+ var n;
582
+ n = name.trim();
583
+ if ((n.startsWith('"') && n.endsWith('"')) || (n.startsWith("'") && n.endsWith("'"))) {
584
+ n = n.slice(1, -1);
585
+ }
586
+ return n;
587
+ };
588
+
475
589
  parseAttributeBlock = function(source, _style, _location = null) {
476
590
  var attrs, cleanName, colonIdx, expr, j, len, name, pair, pairs, trimmed, value;
477
591
  attrs = [];
@@ -293,7 +293,7 @@ printElement = function(path, o, printFn) {
293
293
  }
294
294
  childDocs = (ref3 = path.map(printFn, 'children')) != null ? ref3 : [];
295
295
  joined = joinChildrenWithBlanks(children, childDocs, o);
296
- return join(hardline, [header, indent(joined)]);
296
+ return [header, indent([hardline, joined])];
297
297
  };
298
298
 
299
299
  // ─── ImplicitDiv ───────────────────────────────────────────
@@ -317,7 +317,7 @@ printImplicitDiv = function(path, o, printFn) {
317
317
  }
318
318
  childDocs = (ref3 = path.map(printFn, 'children')) != null ? ref3 : [];
319
319
  joined = joinChildrenWithBlanks(children, childDocs, o);
320
- return join(hardline, [header, indent(joined)]);
320
+ return [header, indent([hardline, joined])];
321
321
  };
322
322
 
323
323
  // ─── Output ────────────────────────────────────────────────
@@ -335,7 +335,7 @@ printOutput = function(path, o, printFn) {
335
335
  }
336
336
  childDocs = (ref2 = path.map(printFn, 'children')) != null ? ref2 : [];
337
337
  joined = joinChildrenWithBlanks(children, childDocs, o);
338
- return join(hardline, [`${marker} ${expr}`, indent(joined)]);
338
+ return [`${marker} ${expr}`, indent([hardline, joined])];
339
339
  };
340
340
 
341
341
  // ─── Control Flow ──────────────────────────────────────────
@@ -403,7 +403,7 @@ printFlow = function(path, o, printFn) {
403
403
  });
404
404
  return join(hardline, ['-', childLines.join('\n')]);
405
405
  }
406
- return join(hardline, [header, indent(join(hardline, (ref2 = path.map(printFn, 'children')) != null ? ref2 : []))]);
406
+ return [header, indent([hardline, join(hardline, (ref2 = path.map(printFn, 'children')) != null ? ref2 : [])])];
407
407
  };
408
408
 
409
409
  printMergedFlow = function(path, o, printFn) {
@@ -499,41 +499,65 @@ detectStyle = function(node, o) {
499
499
  };
500
500
 
501
501
  formatAttributes = function(node, style, o) {
502
- var attr, attrs, expr, k, len, name, parts, ref, ref1, ref2, val;
502
+ var attr, attrs, bareParts, expr, k, len, name, parts, ref, ref1, ref2, val;
503
503
  attrs = (ref = node.attributes) != null ? ref : [];
504
504
  if (!(attrs.length > 0)) {
505
505
  return '';
506
506
  }
507
- parts = [];
508
- for (k = 0, len = attrs.length; k < len; k++) {
509
- attr = attrs[k];
510
- if (attr.spread) {
511
- expr = (ref1 = attr.expression.source) != null ? ref1 : '';
507
+ // Bare style: HTML-style key="val" key2={expr} — space-separated
508
+ if (style === 'bare') {
509
+ bareParts = (function() {
510
+ var k, len, ref1, ref2, results;
511
+ results = [];
512
+ for (k = 0, len = attrs.length; k < len; k++) {
513
+ attr = attrs[k];
514
+ if (attr.spread) {
515
+ expr = (ref1 = attr.expression.source) != null ? ref1 : '';
516
+ if (o.coffeeScriptFormat) {
517
+ expr = formatCoffeeScript(expr, o);
518
+ }
519
+ results.push(`{${expr}...}`);
520
+ } else if (attr.shorthand) {
521
+ results.push(attr.name);
522
+ } else {
523
+ results.push(`${attr.name}=${(ref2 = attr.value.source) != null ? ref2 : ''}`);
524
+ }
525
+ }
526
+ return results;
527
+ })();
528
+ return ` ${bareParts.join(' ')}`;
529
+ } else {
530
+ parts = [];
531
+ for (k = 0, len = attrs.length; k < len; k++) {
532
+ attr = attrs[k];
533
+ if (attr.spread) {
534
+ expr = (ref1 = attr.expression.source) != null ? ref1 : '';
535
+ if (o.coffeeScriptFormat) {
536
+ expr = formatCoffeeScript(expr, o);
537
+ }
538
+ parts.push(style === 'parens' ? `...${expr}` : `{${expr}...}`);
539
+ continue;
540
+ }
541
+ name = attr.name;
542
+ val = (ref2 = attr.value.source) != null ? ref2 : '';
512
543
  if (o.coffeeScriptFormat) {
513
- expr = formatCoffeeScript(expr, o);
544
+ val = formatCoffeeScript(val, o);
545
+ }
546
+ if (attr.shorthand) {
547
+ parts.push(name);
548
+ } else {
549
+ parts.push(`${name}: ${val}`);
514
550
  }
515
- parts.push(style === 'parens' ? `...${expr}` : `{${expr}...}`);
516
- continue;
517
- }
518
- name = attr.name;
519
- val = (ref2 = attr.value.source) != null ? ref2 : '';
520
- if (o.coffeeScriptFormat) {
521
- val = formatCoffeeScript(val, o);
522
551
  }
523
- if (attr.shorthand) {
524
- parts.push(name);
525
- } else {
526
- parts.push(`${name}: ${val}`);
552
+ switch (style) {
553
+ case 'braces':
554
+ return `{ ${parts.join(', ')} }`;
555
+ case 'parens':
556
+ return `( ${parts.join(', ')} )`;
557
+ default:
558
+ return parts.join(', ');
527
559
  }
528
560
  }
529
- switch (style) {
530
- case 'braces':
531
- return `{ ${parts.join(', ')} }`;
532
- case 'parens':
533
- return `( ${parts.join(', ')} )`;
534
- default:
535
- return parts.join(', ');
536
- }
537
561
  };
538
562
 
539
563
  // ─── CoffeeScript Embed (for Prettier embed) ───────────────