@falsefalse/prettier-plugin-handlebars 0.0.1 → 0.0.3
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/LICENSE +2 -1
- package/README.md +19 -15
- package/dist/{errors.d.ts → core/errors.d.ts} +7 -0
- package/dist/{errors.js → core/errors.js} +10 -0
- package/dist/core/html.d.ts +2 -0
- package/dist/core/html.js +32 -0
- package/dist/core/source.d.ts +11 -0
- package/dist/core/source.js +27 -0
- package/dist/{whitespace.d.ts → core/whitespace.d.ts} +5 -0
- package/dist/{whitespace.js → core/whitespace.js} +18 -0
- package/dist/dialects/handlebars/tokens.d.ts +23 -6
- package/dist/dialects/handlebars/tokens.js +15 -8
- package/dist/expression.js +8 -8
- package/dist/parse/lex.d.ts +86 -0
- package/dist/parse/lex.js +274 -0
- package/dist/parse/lookahead.d.ts +35 -0
- package/dist/parse/lookahead.js +305 -0
- package/dist/parse/nodes.d.ts +38 -0
- package/dist/parse/nodes.js +161 -0
- package/dist/parser.d.ts +0 -2
- package/dist/parser.js +271 -931
- package/dist/plugin.d.ts +2 -1
- package/dist/plugin.js +3 -2
- package/dist/printer.d.ts +1 -6
- package/dist/printer.js +72 -35
- package/dist/types.d.ts +2 -2
- package/docs/EDITOR_SETUP.md +0 -1
- package/package.json +3 -6
- /package/dist/{scan.d.ts → core/scan.d.ts} +0 -0
- /package/dist/{scan.js → core/scan.js} +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPrettierIgnoreDirective = getPrettierIgnoreDirective;
|
|
4
|
+
exports.findPrettierIgnoreEnd = findPrettierIgnoreEnd;
|
|
5
|
+
exports.textNode = textNode;
|
|
6
|
+
exports.createUnmatchedNode = createUnmatchedNode;
|
|
7
|
+
exports.contentOffset = contentOffset;
|
|
8
|
+
exports.createMustache = createMustache;
|
|
9
|
+
exports.createStatement = createStatement;
|
|
10
|
+
exports.commentBody = commentBody;
|
|
11
|
+
exports.createComment = createComment;
|
|
12
|
+
/* Turning a token into the node it stands for. The span is the token's, so nothing here scans:
|
|
13
|
+
* what a construct covers was already settled by the time it gets here. */
|
|
14
|
+
const source_1 = require("../core/source");
|
|
15
|
+
const expression_1 = require("../expression");
|
|
16
|
+
const lex_1 = require("./lex");
|
|
17
|
+
const lookahead_1 = require("./lookahead");
|
|
18
|
+
/**
|
|
19
|
+
* The directive has to *be* the comment, not appear somewhere inside it: on `includes`, a
|
|
20
|
+
* comment merely mentioning `prettier-ignore` would silently suppress the next node, and one
|
|
21
|
+
* mentioning `prettier-ignore-start` would open a region.
|
|
22
|
+
*/
|
|
23
|
+
function getPrettierIgnoreDirective(rawContent) {
|
|
24
|
+
switch (rawContent.toLowerCase().replace(/^\s*!(?:-{2})?/u, '').trim()) {
|
|
25
|
+
case 'prettier-ignore-start':
|
|
26
|
+
return 'start';
|
|
27
|
+
case 'prettier-ignore-end':
|
|
28
|
+
return 'end';
|
|
29
|
+
case 'prettier-ignore':
|
|
30
|
+
return 'next';
|
|
31
|
+
default:
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function findPrettierIgnoreEnd(text, position) {
|
|
36
|
+
for (const token of (0, lookahead_1.mustachesFrom)(text, position)) {
|
|
37
|
+
/* Kind first: `commentBody` and the directive lookup are wasted on every mustache, block and
|
|
38
|
+
* partial the scan walks past on the way. */
|
|
39
|
+
if (token.kind === 'comment' && getPrettierIgnoreDirective(commentBody(token)) === 'end') {
|
|
40
|
+
return token.end;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/** A run of source kept as text. `verbatim` means the printer reproduces it rather than reflowing. */
|
|
46
|
+
function textNode(text, start, end, rangeOffset, verbatim = false) {
|
|
47
|
+
const node = verbatim
|
|
48
|
+
? { type: 'TextNode', chars: text.slice(start, end), verbatim }
|
|
49
|
+
: { type: 'TextNode', chars: text.slice(start, end) };
|
|
50
|
+
return (0, source_1.withRange)(node, rangeOffset + start, rangeOffset + end);
|
|
51
|
+
}
|
|
52
|
+
function createUnmatchedNode(text, start, end, rangeOffset) {
|
|
53
|
+
return (0, source_1.withRange)({ type: 'UnmatchedNode', raw: text.slice(start, end) }, rangeOffset + start, rangeOffset + end);
|
|
54
|
+
}
|
|
55
|
+
/** Where `content` begins inside the tag spanning [tagStart, tagEnd), for absolute expression ranges. */
|
|
56
|
+
function contentOffset(text, tagStart, tagEnd, content) {
|
|
57
|
+
const at = text.slice(tagStart, tagEnd).indexOf(content);
|
|
58
|
+
return at === -1 ? tagStart : tagStart + at;
|
|
59
|
+
}
|
|
60
|
+
/* The parts every inline statement shares: its call, and the `~` markers on its delimiters. */
|
|
61
|
+
function statementBase(text, token, position, rangeOffset, content) {
|
|
62
|
+
return {
|
|
63
|
+
...(0, expression_1.parseCall)(content, rangeOffset + contentOffset(text, position, token.end, content)),
|
|
64
|
+
...(token.trimOpen ? { trimOpen: true } : {}),
|
|
65
|
+
...(token.trimClose ? { trimClose: true } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A mustache built from whatever token is in hand, whether or not it reads as one.
|
|
70
|
+
*
|
|
71
|
+
* The recovery paths use it for a block that never closes and for a stray `{{else}}` or
|
|
72
|
+
* `{{/if}}` in a position that cannot reject them.
|
|
73
|
+
*/
|
|
74
|
+
function createMustache(text, token, position, rangeOffset) {
|
|
75
|
+
/* Annotated, not inferred: `withOptionalRange` is generic, so an unannotated literal widens
|
|
76
|
+
* `type` to `string` and stops matching the node union. */
|
|
77
|
+
const node = {
|
|
78
|
+
type: 'MustacheStatement',
|
|
79
|
+
triple: token.triple,
|
|
80
|
+
...statementBase(text, token, position, rangeOffset, token.content),
|
|
81
|
+
};
|
|
82
|
+
return (0, source_1.withOptionalRange)(node, rangeOffset + position, rangeOffset + token.end);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The node for a token that stands on its own, or null for the three kinds - a block and the two
|
|
86
|
+
* terminators - whose handling depends on where they appear.
|
|
87
|
+
*
|
|
88
|
+
* Every context that reads a mustache needs this dispatch: a program body, an attribute list,
|
|
89
|
+
* the inside of a value. Written out three times, they had drifted at the recovery arms.
|
|
90
|
+
*/
|
|
91
|
+
function createStatement(text, token, position, rangeOffset) {
|
|
92
|
+
const start = rangeOffset + position;
|
|
93
|
+
const end = rangeOffset + token.end;
|
|
94
|
+
if (token.kind === 'comment') {
|
|
95
|
+
return createComment(token, start, end);
|
|
96
|
+
}
|
|
97
|
+
if (token.kind === 'partial') {
|
|
98
|
+
const node = {
|
|
99
|
+
type: 'PartialStatement',
|
|
100
|
+
...statementBase(text, token, position, rangeOffset, token.content),
|
|
101
|
+
};
|
|
102
|
+
return (0, source_1.withOptionalRange)(node, start, end);
|
|
103
|
+
}
|
|
104
|
+
/* Before the mustache arm: a decorator is a mustache token carrying a `*`. */
|
|
105
|
+
if (token.specialForm === 'decorator') {
|
|
106
|
+
const node = {
|
|
107
|
+
type: 'DecoratorStatement',
|
|
108
|
+
...statementBase(text, token, position, rangeOffset, token.content.slice(1).trim()),
|
|
109
|
+
};
|
|
110
|
+
return (0, source_1.withOptionalRange)(node, start, end);
|
|
111
|
+
}
|
|
112
|
+
return token.kind === 'mustache' ? createMustache(text, token, position, rangeOffset) : null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A comment's body, with the tag's own `~` markers taken off. They are whitespace control, not
|
|
116
|
+
* text: printing `rawContent` straight through emits them as body, turning `{{~! x ~}}` into
|
|
117
|
+
* `{{! ~! x ~ }}` and dropping the stripping the author asked for.
|
|
118
|
+
*/
|
|
119
|
+
function commentBody(token) {
|
|
120
|
+
let content = token.rawContent;
|
|
121
|
+
if (token.trimOpen) {
|
|
122
|
+
content = content.replace(/^([\t ]*)~/u, '$1');
|
|
123
|
+
}
|
|
124
|
+
/* A block comment's closing `~` follows the `--`, so it never reached `rawContent`. */
|
|
125
|
+
if (token.trimClose) {
|
|
126
|
+
content = content.replace(/~([\t ]*)$/u, '$1');
|
|
127
|
+
}
|
|
128
|
+
return content;
|
|
129
|
+
}
|
|
130
|
+
function createComment(token, start, end) {
|
|
131
|
+
const content = commentBody(token);
|
|
132
|
+
const isBlockStyle = /^\s*!-{2}/.test(content);
|
|
133
|
+
/* express-hbs' layout directive is `{{!< name}}`, with nothing between the `!` and the `<`, so
|
|
134
|
+
* the gap is what distinguishes it. Recognising it by body alone would print the ordinary
|
|
135
|
+
* comment `{{! < name}}` as a directive, silently wrapping the page in a layout. */
|
|
136
|
+
const isLayout = /^!<\s*\S/u.test(content.trim());
|
|
137
|
+
/* Only a block comment's `--` is a marker. Stripping up to two dashes regardless cannot tell
|
|
138
|
+
* it from a body that opens with one, which turns `{{!-foo}}` into `{{! foo }}`.
|
|
139
|
+
*
|
|
140
|
+
* Nothing is stripped from the end: the tokenizer stops before the closing delimiter already,
|
|
141
|
+
* so doing it again would delete a `--` the author wrote. */
|
|
142
|
+
const body = content.replace(isBlockStyle ? /^[\t ]*!--/u : /^[\t ]*!/u, '');
|
|
143
|
+
/* Trailing whitespace comes off first. A space between `{{!--` and the newline is invisible in
|
|
144
|
+
* the source and left the body not *starting* with one, which silently turned off the
|
|
145
|
+
* re-indent below - so `{{!-- \n x\n--}}` and `{{!--\n x\n--}}` printed differently. */
|
|
146
|
+
const trimmed = body.replace(/[ \t]+$/gm, '');
|
|
147
|
+
/* A body the author started on its own line keeps its leading newline; the printer reads that
|
|
148
|
+
* to decide whether to re-indent it. ASCII whitespace, not `\s`: a non-breaking space is
|
|
149
|
+
* content the author put there, and `\s` deleted one off the front of a comment body. */
|
|
150
|
+
const value = trimmed.startsWith('\n') ? trimmed : trimmed.replace(lex_1.leadingWhitespace, '');
|
|
151
|
+
const isMultiline = /\n/.test(content);
|
|
152
|
+
return (0, source_1.withOptionalRange)({
|
|
153
|
+
type: 'CommentStatement',
|
|
154
|
+
value,
|
|
155
|
+
multiline: isMultiline,
|
|
156
|
+
block: isBlockStyle || isMultiline,
|
|
157
|
+
...(isLayout ? { layout: true } : {}),
|
|
158
|
+
...(token.trimOpen ? { trimOpen: true } : {}),
|
|
159
|
+
...(token.trimClose ? { trimClose: true } : {}),
|
|
160
|
+
}, start, end);
|
|
161
|
+
}
|
package/dist/parser.d.ts
CHANGED