coffeehaml 0.7.3 → 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 = [];
@@ -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) ───────────────