@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.
@@ -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
@@ -1,4 +1,2 @@
1
1
  import { Program } from './types';
2
- import { locEnd, locStart } from 'template-format-core';
3
- export { locEnd, locStart };
4
2
  export declare function parse(text: string): Program;