coffeehaml 0.7.5 → 0.7.7

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/printer.js DELETED
@@ -1,583 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- // printer.coffee — AST → Prettier Doc IR
3
- // Core formatting engine for CoffeeHaml Prettier plugin
4
- var MergedStatements, VOID_ELEMENTS, _prettier, _require, analyzeBlankLines, defaultOpts, detectStyle, formatAttributes, formatTag, group, hardline, indent, isSingleInlineChild, isVoidElement, join, joinChildrenWithBlanks, mergeAllStatements, opts, printComment, printControlFlow, printDoc, printDoctype, printElement, printFilter, printFlow, printImplicitDiv, printMergedFlow, printNode, printOutput, reflowCommentText;
5
-
6
- import {
7
- Document,
8
- Element,
9
- ImplicitDiv,
10
- Text,
11
- Output,
12
- ControlFlow,
13
- Comment,
14
- Filter,
15
- Doctype,
16
- Node,
17
- Expression,
18
- Attribute,
19
- SpreadAttribute
20
- } from '../ast.js';
21
-
22
- import {
23
- formatCoffeeScript,
24
- formatCoffeeScriptBlock
25
- } from './coffeescript-formatter.js';
26
-
27
- import {
28
- createRequire
29
- } from 'module';
30
-
31
- _require = createRequire(import.meta.url);
32
-
33
- _prettier = _require('prettier');
34
-
35
- ({group, indent, hardline, join} = _prettier.doc.builders);
36
-
37
- // ─── Format Options ────────────────────────────────────────
38
- // CoffeeHamlFormatOptions shape (runtime):
39
- // tagCase, implicitDivExpansion, maxChainLength, inlineThreshold
40
- // voidElementStyle, attributeStyle, attributeMultilineThreshold
41
- // attributeSort, quoteStyle, coffeeScriptFormat, methodChainAlign
42
- // blankLineHandling, trailingWhitespace, continuationStyle
43
- // controlFlowInline, statementMerging, commentFormat
44
- // tabWidth, useTabs, printWidth, originalText?
45
- defaultOpts = {
46
- tagCase: 'preserve',
47
- implicitDivExpansion: false,
48
- maxChainLength: 4,
49
- inlineThreshold: -1,
50
- voidElementStyle: 'self-closing',
51
- attributeStyle: 'preserve',
52
- attributeMultilineThreshold: 1,
53
- attributeSort: 'none',
54
- quoteStyle: 'preserve',
55
- coffeeScriptFormat: true,
56
- methodChainAlign: true,
57
- blankLineHandling: 'preserve',
58
- trailingWhitespace: 'remove',
59
- continuationStyle: 'indent',
60
- controlFlowInline: false,
61
- statementMerging: 'preserve',
62
- commentFormat: false,
63
- tabWidth: 2,
64
- useTabs: false,
65
- printWidth: 80,
66
- originalText: void 0
67
- };
68
-
69
- opts = function(p) {
70
- return p.__opts || defaultOpts;
71
- };
72
-
73
- MergedStatements = (function() {
74
- // ─── MergedStatements wrapper ──────────────────────────────
75
- class MergedStatements {
76
- constructor(statements) {
77
- this.statements = statements;
78
- }
79
-
80
- };
81
-
82
- MergedStatements.prototype.kind = 'MergedStatements';
83
-
84
- MergedStatements.prototype.statements = [];
85
-
86
- return MergedStatements;
87
-
88
- }).call(this);
89
-
90
- // ─── Constants ─────────────────────────────────────────────
91
- VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
92
-
93
- isVoidElement = function(tag) {
94
- return VOID_ELEMENTS.has(tag.toLowerCase());
95
- };
96
-
97
- isSingleInlineChild = function(children) {
98
- return children.length === 1 && (children[0] instanceof Text || children[0] instanceof Output);
99
- };
100
-
101
- // ─── Blank-line-aware join ─────────────────────────────────
102
- joinChildrenWithBlanks = function(nodes, docs, o) {
103
- var hasBlank, i, k, ref, ref1, result;
104
- if (docs.length === 0) {
105
- return '';
106
- }
107
- if (docs.length === 1) {
108
- return docs[0];
109
- }
110
- result = [];
111
- for (i = k = 0, ref = docs.length; (0 <= ref ? k < ref : k > ref); i = 0 <= ref ? ++k : --k) {
112
- if (i > 0) {
113
- hasBlank = ((ref1 = nodes[i]) != null ? ref1._blankBefore : void 0) || false;
114
- result.push(hasBlank ? [hardline, hardline] : hardline);
115
- }
116
- result.push(docs[i]);
117
- }
118
- return result;
119
- };
120
-
121
- analyzeBlankLines = function(children, originalText, locations) {
122
- var between, currStartOffset, i, k, node, prev, prevEndOffset, ref, results;
123
- if (!(originalText && children.length > 1)) {
124
- return;
125
- }
126
- results = [];
127
- for (i = k = 0, ref = children.length; (0 <= ref ? k < ref : k > ref); i = 0 <= ref ? ++k : --k) {
128
- node = children[i];
129
- if (!(node != null ? node.location : void 0)) {
130
- continue;
131
- }
132
- prev = children[i - 1];
133
- if (!(prev != null ? prev.location : void 0)) {
134
- continue;
135
- }
136
- // Check for blank line in source between prev end and this node start
137
- prevEndOffset = prev.location.offset + prev.location.length;
138
- currStartOffset = node.location.offset;
139
- between = originalText.slice(prevEndOffset, currStartOffset);
140
- if (/\n\s*\n/.test(between)) {
141
- results.push(node._blankBefore = true);
142
- } else {
143
- results.push(void 0);
144
- }
145
- }
146
- return results;
147
- };
148
-
149
- // ─── Merge consecutive statements ──────────────────────────
150
- mergeAllStatements = function(children) {
151
- var child, i, j, next, result;
152
- if (!((children != null ? children.length : void 0) > 1)) {
153
- return children;
154
- }
155
- result = [];
156
- i = 0;
157
- while (i < children.length) {
158
- child = children[i];
159
- if (child instanceof ControlFlow && child.controlKind === 'statement' && child.children.length === 0) {
160
- group = [child];
161
- j = i + 1;
162
- while (j < children.length) {
163
- next = children[j];
164
- if (next instanceof ControlFlow && next.controlKind === 'statement' && next.children.length === 0) {
165
- group.push(next);
166
- j++;
167
- } else {
168
- break;
169
- }
170
- }
171
- if (group.length > 1) {
172
- result.push(new MergedStatements(group));
173
- i = j;
174
- continue;
175
- }
176
- }
177
- result.push(child);
178
- i++;
179
- }
180
- return result;
181
- };
182
-
183
- // ─── Main entry ────────────────────────────────────────────
184
- export var print = function(path, o, printFn) {
185
- var node;
186
- node = path.node;
187
- if (!node) {
188
- return '';
189
- }
190
- // Hang options on path for nested lookups
191
- path.__opts = o;
192
- return printNode(path, o, printFn);
193
- };
194
-
195
- printNode = function(path, o, printFn) {
196
- var node;
197
- node = path.node;
198
- if (!node) {
199
- return '';
200
- }
201
- if (node instanceof Document) {
202
- return printDoc(path, o, printFn);
203
- }
204
- if (node instanceof Element) {
205
- return printElement(path, o, printFn);
206
- }
207
- if (node instanceof ImplicitDiv) {
208
- return printImplicitDiv(path, o, printFn);
209
- }
210
- if (node instanceof Text) {
211
- return node.value;
212
- }
213
- if (node instanceof Output) {
214
- return printOutput(path, o, printFn);
215
- }
216
- if (node instanceof ControlFlow) {
217
- return printControlFlow(path, o, printFn);
218
- }
219
- if (node instanceof MergedStatements) {
220
- return printMergedFlow(path, o, printFn);
221
- }
222
- if (node instanceof Comment) {
223
- return printComment(path, o, printFn);
224
- }
225
- if (node instanceof Filter) {
226
- return printFilter(path, o, printFn);
227
- }
228
- if (node instanceof Doctype) {
229
- return printDoctype(path, o);
230
- }
231
- return '';
232
- };
233
-
234
- // ─── Document ──────────────────────────────────────────────
235
- printDoc = function(path, o, printFn) {
236
- var childDocs, k, len, n, next, node, ref, ref1;
237
- node = path.node;
238
- // Pre-pass: merge statements if enabled
239
- if (o.statementMerging === 'merge') {
240
- node.children = mergeAllStatements(node.children);
241
- }
242
- // Pre-pass: analyze blank lines
243
- if (o.blankLineHandling === 'preserve' && o.originalText) {
244
- ref = node.children;
245
- for (k = 0, len = ref.length; k < len; k++) {
246
- n = ref[k];
247
- next = node.children[node.children.indexOf(n) + 1];
248
- if (next) {
249
- analyzeBlankLines([n, next], o.originalText);
250
- }
251
- }
252
- }
253
- // Print children
254
- childDocs = (ref1 = path.map(printFn, 'children')) != null ? ref1 : [];
255
- return join(hardline, childDocs);
256
- };
257
-
258
- // ─── Element ───────────────────────────────────────────────
259
- printElement = function(path, o, printFn) {
260
- var attrStyle, attrs, childDoc, childDocs, children, classes, header, id, isVoid, joined, node, ref, ref1, ref2, ref3, selfClose, tag;
261
- node = path.node;
262
- tag = formatTag(node.tag, o);
263
- // Classes and ID
264
- classes = node.classes.map(function(c) {
265
- return `.${c}`;
266
- }).join('');
267
- id = node.id ? `#${node.id}` : '';
268
- // Attributes
269
- attrStyle = detectStyle(node, o);
270
- attrs = formatAttributes(node, attrStyle, o);
271
- // Self-close marker
272
- isVoid = typeof node.tag === 'string' && isVoidElement(node.tag);
273
- selfClose = '';
274
- if (isVoid) {
275
- if (o.voidElementStyle === 'self-closing') {
276
- selfClose = '/';
277
- } else if (node.isSelfClosing) {
278
- selfClose = '/';
279
- }
280
- } else if (node.isSelfClosing) {
281
- selfClose = '/';
282
- }
283
- header = `%${tag}${classes}${id}${attrs}${selfClose}`;
284
- // Children
285
- children = (ref = node.children) != null ? ref : [];
286
- if (children.length === 0) {
287
- return header;
288
- }
289
- // Inline child
290
- if (isSingleInlineChild(children) && o.controlFlowInline !== false) {
291
- childDoc = (ref1 = (ref2 = path.map(printFn, 'children')) != null ? ref2[0] : void 0) != null ? ref1 : '';
292
- return `${header} ${childDoc}`;
293
- }
294
- childDocs = (ref3 = path.map(printFn, 'children')) != null ? ref3 : [];
295
- joined = joinChildrenWithBlanks(children, childDocs, o);
296
- return [header, indent([hardline, joined])];
297
- };
298
-
299
- // ─── ImplicitDiv ───────────────────────────────────────────
300
- printImplicitDiv = function(path, o, printFn) {
301
- var attrStyle, attrs, childDoc, childDocs, children, classes, header, id, joined, node, ref, ref1, ref2, ref3;
302
- node = path.node;
303
- classes = node.classes.map(function(c) {
304
- return `.${c}`;
305
- }).join('');
306
- id = node.id ? `#${node.id}` : '';
307
- attrStyle = detectStyle(node, o);
308
- attrs = formatAttributes(node, attrStyle, o);
309
- header = `${classes}${id}${attrs}`;
310
- children = (ref = node.children) != null ? ref : [];
311
- if (children.length === 0) {
312
- return header;
313
- }
314
- if (isSingleInlineChild(children)) {
315
- childDoc = (ref1 = (ref2 = path.map(printFn, 'children')) != null ? ref2[0] : void 0) != null ? ref1 : '';
316
- return `${header} ${childDoc}`;
317
- }
318
- childDocs = (ref3 = path.map(printFn, 'children')) != null ? ref3 : [];
319
- joined = joinChildrenWithBlanks(children, childDocs, o);
320
- return [header, indent([hardline, joined])];
321
- };
322
-
323
- // ─── Output ────────────────────────────────────────────────
324
- printOutput = function(path, o, printFn) {
325
- var childDocs, children, expr, joined, marker, node, ref, ref1, ref2;
326
- node = path.node;
327
- marker = node.outputKind === 'unescaped' ? '!=' : '=';
328
- expr = (ref = node.expression.source) != null ? ref : '';
329
- if (o.coffeeScriptFormat) {
330
- expr = formatCoffeeScript(expr, o);
331
- }
332
- children = (ref1 = node.children) != null ? ref1 : [];
333
- if (children.length === 0) {
334
- return `${marker} ${expr}`;
335
- }
336
- childDocs = (ref2 = path.map(printFn, 'children')) != null ? ref2 : [];
337
- joined = joinChildrenWithBlanks(children, childDocs, o);
338
- return [`${marker} ${expr}`, indent([hardline, joined])];
339
- };
340
-
341
- // ─── Control Flow ──────────────────────────────────────────
342
- printControlFlow = function(path, o, printFn) {
343
- return printFlow(path, o, printFn);
344
- };
345
-
346
- printFlow = function(path, o, printFn) {
347
- var childLines, children, expr, header, kind, node, ref, ref1, ref2, sep;
348
- node = path.node;
349
- kind = node.controlKind;
350
- // Format expression
351
- expr = (ref = node.expression.source) != null ? ref : '';
352
- if (o.coffeeScriptFormat && kind !== 'statement') {
353
- expr = formatCoffeeScript(expr, o);
354
- }
355
- // Build header
356
- header = (function() {
357
- switch (kind) {
358
- case 'statement':
359
- if (expr) {
360
- return `- ${expr}`;
361
- } else {
362
- return '-';
363
- }
364
- break;
365
- case 'else':
366
- return '- else';
367
- case 'else if':
368
- return `- else if ${expr}`;
369
- default:
370
- return `- ${kind} ${expr}`;
371
- }
372
- })();
373
- children = (ref1 = node.children) != null ? ref1 : [];
374
- // Inline expansion (controlFlowInline)
375
- if (o.controlFlowInline && children.length > 0 && (kind === 'if' || kind === 'unless' || kind === 'for' || kind === 'while')) {
376
- if (children.length === 1 && (children[0] instanceof Element || children[0] instanceof ImplicitDiv)) {
377
- sep = kind === 'if' || kind === 'unless' ? ' then ' : ' ';
378
- return `${header}${sep}${printNode(path.map(printFn, 'children.0'), o, printFn)}`;
379
- }
380
- }
381
- if (children.length === 0) {
382
- return header;
383
- }
384
- // Re-parsed merged statements: statement-kind with empty expr + TEXT children
385
- // Use baked indentation (matching printMergedFlow) to avoid Prettier indent quirks
386
- if (kind === 'statement' && !expr && children.every(function(c) {
387
- return c instanceof Text || c instanceof Output;
388
- })) {
389
- childLines = children.map(function(c) {
390
- var val;
391
- val = (function() {
392
- var ref2, ref3;
393
- switch (false) {
394
- case !(c instanceof Text):
395
- return c.value;
396
- case !(c instanceof Output):
397
- return (ref2 = (ref3 = c.expression) != null ? ref3.source : void 0) != null ? ref2 : '';
398
- default:
399
- return '';
400
- }
401
- })();
402
- return ' ' + val;
403
- });
404
- return join(hardline, ['-', childLines.join('\n')]);
405
- }
406
- return [header, indent([hardline, join(hardline, (ref2 = path.map(printFn, 'children')) != null ? ref2 : [])])];
407
- };
408
-
409
- printMergedFlow = function(path, o, printFn) {
410
- var lines, node;
411
- node = path.node;
412
- lines = node.statements.map(function(stmt) {
413
- var expr, ref;
414
- expr = (ref = stmt.expression.source) != null ? ref : '';
415
- if (o.coffeeScriptFormat) {
416
- expr = formatCoffeeScript(expr, o);
417
- }
418
- return ' ' + expr;
419
- });
420
- return join(hardline, ['-', lines.join('\n')]);
421
- };
422
-
423
- // ─── Comment ───────────────────────────────────────────────
424
- printComment = function(path, o, _printFn) {
425
- var node, text;
426
- node = path.node;
427
- if (node.commentKind === 'html') {
428
- return `/ ${node.text}`;
429
- }
430
- text = node.text || '';
431
- if (o.commentFormat && text.length > o.printWidth * 0.7) {
432
- text = reflowCommentText(text, o.printWidth);
433
- }
434
- return `-# ${text}`;
435
- };
436
-
437
- reflowCommentText = function(text, width) {
438
- var current, k, len, lines, word, words;
439
- words = text.split(/\s+/);
440
- lines = [];
441
- current = '';
442
- for (k = 0, len = words.length; k < len; k++) {
443
- word = words[k];
444
- if (current.length + word.length + 1 > width - 3) { // 3 = "-# "
445
- if (current) {
446
- lines.push(current.trim());
447
- }
448
- current = word;
449
- } else {
450
- current += current ? ' ' + word : word;
451
- }
452
- }
453
- if (current) {
454
- lines.push(current.trim());
455
- }
456
- return lines.join('\n-# ');
457
- };
458
-
459
- // ─── Filter ────────────────────────────────────────────────
460
- printFilter = function(path, o, _printFn) {
461
- var header, indented, node;
462
- node = path.node;
463
- header = `:${node.filterName}`;
464
- if (node.content) {
465
- indented = node.content.split('\n').map(function(l) {
466
- return ' ' + l;
467
- }).join('\n');
468
- return `${header}\n${indented}`;
469
- } else {
470
- return header;
471
- }
472
- };
473
-
474
- // ─── Doctype ───────────────────────────────────────────────
475
- printDoctype = function(path, o) {
476
- var node;
477
- node = path.node;
478
- return `!!! ${node.value || 'html'}`;
479
- };
480
-
481
- // ─── Tag formatting ────────────────────────────────────────
482
- formatTag = function(tag, o) {
483
- if (tag instanceof Expression) {
484
- return tag.source;
485
- }
486
- if (o.tagCase === 'lowercase' && /^[a-z]/.test(tag)) {
487
- return tag.toLowerCase();
488
- }
489
- return tag;
490
- };
491
-
492
- // ─── Attribute style detection ─────────────────────────────
493
- detectStyle = function(node, o) {
494
- var ref;
495
- if (o.attributeStyle !== 'preserve') {
496
- return o.attributeStyle;
497
- }
498
- return (ref = node.attrStyle) != null ? ref : 'bare';
499
- };
500
-
501
- formatAttributes = function(node, style, o) {
502
- var attr, attrs, bareParts, expr, k, len, name, parts, ref, ref1, ref2, val;
503
- attrs = (ref = node.attributes) != null ? ref : [];
504
- if (!(attrs.length > 0)) {
505
- return '';
506
- }
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 : '';
543
- if (o.coffeeScriptFormat) {
544
- val = formatCoffeeScript(val, o);
545
- }
546
- if (attr.shorthand) {
547
- parts.push(name);
548
- } else {
549
- parts.push(`${name}: ${val}`);
550
- }
551
- }
552
- switch (style) {
553
- case 'braces':
554
- return `{ ${parts.join(', ')} }`;
555
- case 'parens':
556
- return `( ${parts.join(', ')} )`;
557
- default:
558
- return parts.join(', ');
559
- }
560
- }
561
- };
562
-
563
- // ─── CoffeeScript Embed (for Prettier embed) ───────────────
564
- export var embedCoffeeScript = function(path, _print) {
565
- var expr, node, ref;
566
- node = path.node;
567
- if (!node) {
568
- return null;
569
- }
570
- if (node instanceof Output || node instanceof ControlFlow) {
571
- expr = (ref = node.expression) != null ? ref.source : void 0;
572
- if (!(expr && /[\u0000-\u00ff]/.test(expr))) {
573
- return null;
574
- }
575
- null;
576
- }
577
- return null;
578
- };
579
-
580
- export {
581
- MergedStatements,
582
- mergeAllStatements
583
- };