@malloydata/malloy 0.0.384 → 0.0.386

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.
Files changed (36) hide show
  1. package/dist/api/foundation/config_resolve.js +12 -20
  2. package/dist/internal.d.ts +2 -0
  3. package/dist/internal.js +3 -1
  4. package/dist/lang/prettify/binary-chain.d.ts +3 -0
  5. package/dist/lang/prettify/binary-chain.js +65 -0
  6. package/dist/lang/prettify/block-body.d.ts +4 -0
  7. package/dist/lang/prettify/block-body.js +74 -0
  8. package/dist/lang/prettify/error-listener.d.ts +6 -0
  9. package/dist/lang/prettify/error-listener.js +19 -0
  10. package/dist/lang/prettify/field-properties.d.ts +3 -0
  11. package/dist/lang/prettify/field-properties.js +57 -0
  12. package/dist/lang/prettify/formatter.d.ts +17 -0
  13. package/dist/lang/prettify/formatter.js +145 -0
  14. package/dist/lang/prettify/index.d.ts +19 -0
  15. package/dist/lang/prettify/index.js +139 -0
  16. package/dist/lang/prettify/inline-renderer.d.ts +3 -0
  17. package/dist/lang/prettify/inline-renderer.js +101 -0
  18. package/dist/lang/prettify/leaf.d.ts +9 -0
  19. package/dist/lang/prettify/leaf.js +313 -0
  20. package/dist/lang/prettify/out.d.ts +12 -0
  21. package/dist/lang/prettify/out.js +74 -0
  22. package/dist/lang/prettify/pick-case.d.ts +5 -0
  23. package/dist/lang/prettify/pick-case.js +222 -0
  24. package/dist/lang/prettify/rules.d.ts +13 -0
  25. package/dist/lang/prettify/rules.js +103 -0
  26. package/dist/lang/prettify/sections.d.ts +4 -0
  27. package/dist/lang/prettify/sections.js +261 -0
  28. package/dist/lang/prettify/tokens.d.ts +13 -0
  29. package/dist/lang/prettify/tokens.js +160 -0
  30. package/dist/lang/prettify/types.d.ts +9 -0
  31. package/dist/lang/prettify/types.js +7 -0
  32. package/dist/lang/run-malloy-parser.d.ts +23 -0
  33. package/dist/lang/run-malloy-parser.js +32 -8
  34. package/dist/version.d.ts +1 -1
  35. package/dist/version.js +1 -1
  36. package/package.json +4 -4
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * renderItemInline — flat-string form of a parse-rule's token range.
7
+ *
8
+ * Used by:
9
+ * - section-list inline measurement and bare-item flow-fill
10
+ * - postfix `{…}` inline form
11
+ * - pick / case alignment (rendering values and conditions to strings)
12
+ *
13
+ * Inter-token spacing comes from `leadingAction` in ./tokens, the same
14
+ * classifier the leaf walker (./leaf) consults. Both walkers therefore agree
15
+ * on what spacing goes between any two adjacent tokens; inline measurement
16
+ * predicts actual emission.
17
+ *
18
+ * Walker-specific divergence:
19
+ * - This produces a flat string (no newlines, no indentation).
20
+ * - SEMI emits `; ` (compact-inline form), not a newline.
21
+ * - COMMA emits `, ` (intra-line form), not a newline.
22
+ * - The space-coalescing skip-list omits `\n` (we never emit one) but is
23
+ * otherwise the same as Out.space.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.renderItemInline = renderItemInline;
27
+ const antlr4ts_1 = require("antlr4ts");
28
+ const tokens_1 = require("./tokens");
29
+ function renderItemInline(f, ctx) {
30
+ var _a;
31
+ let buf = '';
32
+ let lastType = null;
33
+ // Coalescing space: skip if buffer is empty or last char already provides
34
+ // separation. Mirrors Out.space() (./out) minus the newline check, since
35
+ // this renderer never emits a newline.
36
+ const space = () => {
37
+ if (buf.length === 0)
38
+ return;
39
+ const last = buf[buf.length - 1];
40
+ if (last === ' ' || last === '(' || last === '[' || last === '.')
41
+ return;
42
+ buf += ' ';
43
+ };
44
+ const trim = () => {
45
+ buf = buf.replace(/ +$/, '');
46
+ };
47
+ for (let i = ctx._start.tokenIndex; i <= ctx._stop.tokenIndex; i++) {
48
+ const t = f.tokens[i];
49
+ if (t.channel === antlr4ts_1.Token.HIDDEN_CHANNEL)
50
+ continue;
51
+ const text = (_a = t.text) !== null && _a !== void 0 ? _a : '';
52
+ if (t.type === tokens_1.L.SQL_BEGIN) {
53
+ const endIdx = (0, tokens_1.findMatching)(f.tokens, i, tokens_1.L.SQL_BEGIN, tokens_1.L.SQL_END);
54
+ const stop = f.tokens[endIdx].stopIndex;
55
+ space();
56
+ buf += f.src.substring(t.startIndex, stop + 1);
57
+ i = endIdx;
58
+ lastType = tokens_1.L.SQL_END;
59
+ continue;
60
+ }
61
+ if (t.type === tokens_1.L.CCURLY) {
62
+ // `{}` empty: no inner space. `{ x }`: both inner spaces.
63
+ if (buf.length > 0 && !buf.endsWith('{') && !buf.endsWith(' '))
64
+ buf += ' ';
65
+ else
66
+ trim();
67
+ buf += '}';
68
+ lastType = t.type;
69
+ continue;
70
+ }
71
+ // Walker-specific divergence: COMMA and SEMI use compact-inline form
72
+ // (`, ` and `; `). The leaf walker (./leaf) emits newlines for these in
73
+ // wrapped contexts.
74
+ if (t.type === tokens_1.L.COMMA) {
75
+ trim();
76
+ buf += ', ';
77
+ lastType = t.type;
78
+ continue;
79
+ }
80
+ if (t.type === tokens_1.L.SEMI) {
81
+ trim();
82
+ buf += '; ';
83
+ lastType = t.type;
84
+ continue;
85
+ }
86
+ // Everything else: classifier-driven leading separator + text + (if a
87
+ // binary op) trailing space. Same shape as the leaf walker's default.
88
+ const action = (0, tokens_1.leadingAction)(lastType, t.type);
89
+ if (action === 'glue')
90
+ trim();
91
+ else if (action === 'space')
92
+ space();
93
+ // 'hug' — emit nothing before
94
+ buf += text;
95
+ if (tokens_1.BINARY_OPS.has(t.type))
96
+ buf += ' ';
97
+ lastType = t.type;
98
+ }
99
+ return buf;
100
+ }
101
+ //# sourceMappingURL=inline-renderer.js.map
@@ -0,0 +1,9 @@
1
+ import { Token } from 'antlr4ts';
2
+ import type { Formatter } from './formatter';
3
+ export declare function note(f: Formatter, tokenType: number, idx: number, endTok: Token): void;
4
+ export declare function flushHiddenBefore(f: Formatter, idx: number): void;
5
+ export declare function startStatementLine(f: Formatter): void;
6
+ export declare function approxInlineSpan(f: Formatter, fromIdx: number, toIdx: number): number;
7
+ export declare function hasCommentsInRange(f: Formatter, fromIdx: number, toIdx: number): boolean;
8
+ export declare function emitVisibleToken(f: Formatter, t: Token, idx: number): void;
9
+ export declare function formatTokenRange(f: Formatter, fromIdx: number, toIdx: number): void;
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Leaf walker: per-token spacing, structural punctuation, comment placement,
7
+ * and the small helpers the rule formatters use to look at adjacent tokens.
8
+ *
9
+ * Per-rule formatters call into here via:
10
+ * - emitVisibleToken — the leaf
11
+ * - flushHiddenBefore — emit pending comments before a target index
12
+ * - note — atomic per-token state update
13
+ * - startStatementLine — newline (consuming `needBlank`) for stmt start
14
+ * - approxInlineSpan — line-budget overestimate for a token range
15
+ * - hasCommentsInRange — comment-presence check (gates inline form)
16
+ * - formatTokenRange — emit a span via the leaf walker
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.note = note;
20
+ exports.flushHiddenBefore = flushHiddenBefore;
21
+ exports.startStatementLine = startStatementLine;
22
+ exports.approxInlineSpan = approxInlineSpan;
23
+ exports.hasCommentsInRange = hasCommentsInRange;
24
+ exports.emitVisibleToken = emitVisibleToken;
25
+ exports.formatTokenRange = formatTokenRange;
26
+ const antlr4ts_1 = require("antlr4ts");
27
+ const tokens_1 = require("./tokens");
28
+ // Update per-token state after emitting a token (or a token-like span).
29
+ function note(f, tokenType, idx, endTok) {
30
+ f.lastEmittedType = tokenType;
31
+ f.prevTokenEndLine = (0, tokens_1.endLineOf)(endTok);
32
+ f.lastEmittedIdx = idx;
33
+ }
34
+ // Emit any hidden-channel tokens (comments) sitting between f.lastEmittedIdx
35
+ // and idx-1, advancing f.lastEmittedIdx so they are not re-emitted by a later
36
+ // call. Visible tokens in the same range (e.g. commas the section-list rule
37
+ // chose to drop) are skipped.
38
+ function flushHiddenBefore(f, idx) {
39
+ if (idx <= f.lastEmittedIdx + 1)
40
+ return;
41
+ for (let j = f.lastEmittedIdx + 1; j < idx; j++) {
42
+ const t = f.tokens[j];
43
+ if (t.channel === antlr4ts_1.Token.HIDDEN_CHANNEL) {
44
+ emitHiddenToken(f, t);
45
+ }
46
+ }
47
+ f.lastEmittedIdx = idx - 1;
48
+ }
49
+ // Hidden-channel tokens (comments). Trailing comments (same line as previous
50
+ // token) attach with a space; leading comments (own line) start a fresh line.
51
+ function emitHiddenToken(f, t) {
52
+ var _a;
53
+ const text = (_a = t.text) !== null && _a !== void 0 ? _a : '';
54
+ const sameLine = f.prevTokenEndLine !== 0 && t.line === f.prevTokenEndLine;
55
+ if (t.type === tokens_1.L.COMMENT_TO_EOL) {
56
+ if (sameLine) {
57
+ f.o.space();
58
+ f.o.text(text.replace(/\s+$/, ''));
59
+ f.o.nl();
60
+ }
61
+ else {
62
+ if (f.o.indent === 0)
63
+ startStatementLine(f);
64
+ else
65
+ f.o.nl();
66
+ f.o.text(text.replace(/\s+$/, ''));
67
+ f.o.nl();
68
+ }
69
+ }
70
+ else if (t.type === tokens_1.L.BLOCK_COMMENT) {
71
+ if (sameLine) {
72
+ f.o.space();
73
+ f.o.text(text);
74
+ f.o.space();
75
+ }
76
+ else {
77
+ if (f.o.indent === 0)
78
+ startStatementLine(f);
79
+ else
80
+ f.o.nl();
81
+ f.o.text(text);
82
+ f.o.nl();
83
+ }
84
+ }
85
+ f.prevTokenEndLine = (0, tokens_1.endLineOf)(t);
86
+ }
87
+ // Either consume `needBlank` (emit blank line) or just newline.
88
+ function startStatementLine(f) {
89
+ if (f.needBlank) {
90
+ f.o.blank();
91
+ f.needBlank = false;
92
+ }
93
+ else {
94
+ f.o.nl();
95
+ }
96
+ }
97
+ // Approximate length of the inline form of tokens [fromIdx, toIdx]: sum of
98
+ // visible token text + 1 char between adjacent tokens. Used for budget checks
99
+ // (paren wrap, pickStatement wrap, etc.). It's an overestimate for dotted-paths
100
+ // and similar (`a.b` is 3 chars, our estimate is 5) but the direction is
101
+ // conservative — we wrap a touch sooner than strictly needed.
102
+ function approxInlineSpan(f, fromIdx, toIdx) {
103
+ var _a;
104
+ let len = 0;
105
+ let prev = -1;
106
+ for (let i = fromIdx; i <= toIdx; i++) {
107
+ const t = f.tokens[i];
108
+ if (t.channel === antlr4ts_1.Token.HIDDEN_CHANNEL)
109
+ continue;
110
+ if (t.type === antlr4ts_1.Token.EOF)
111
+ continue;
112
+ if (prev >= 0)
113
+ len += 1;
114
+ len += ((_a = t.text) !== null && _a !== void 0 ? _a : '').length;
115
+ prev = i;
116
+ }
117
+ return len;
118
+ }
119
+ // Are there any hidden-channel tokens (comments) in [fromIdx, toIdx]? Used to
120
+ // gate inline-form candidates: any path that goes through `renderItemInline`
121
+ // strips comments, so candidates with comments must fall back to wrapped or
122
+ // broken form where the leaf walker preserves them.
123
+ function hasCommentsInRange(f, fromIdx, toIdx) {
124
+ for (let i = fromIdx; i <= toIdx; i++) {
125
+ if (f.tokens[i].channel === antlr4ts_1.Token.HIDDEN_CHANNEL)
126
+ return true;
127
+ }
128
+ return false;
129
+ }
130
+ // Does the paren-pair at [openIdx, closeIdx] have any COMMA at its own depth?
131
+ // (Used to distinguish "function call with multiple args" from "single-arg
132
+ // call" / "empty parens".)
133
+ function hasCommaAtDepth1(f, openIdx, closeIdx) {
134
+ let depth = 0;
135
+ for (let i = openIdx + 1; i < closeIdx; i++) {
136
+ const t = f.tokens[i];
137
+ if (t.channel === antlr4ts_1.Token.HIDDEN_CHANNEL)
138
+ continue;
139
+ if (t.type === tokens_1.L.OPAREN || t.type === tokens_1.L.OBRACK || t.type === tokens_1.L.OCURLY)
140
+ depth++;
141
+ else if (t.type === tokens_1.L.CPAREN || t.type === tokens_1.L.CBRACK || t.type === tokens_1.L.CCURLY)
142
+ depth--;
143
+ else if (t.type === tokens_1.L.COMMA && depth === 0)
144
+ return true;
145
+ }
146
+ return false;
147
+ }
148
+ // The big switch. Each branch ends with `note(...)`.
149
+ function emitVisibleToken(f, t, idx) {
150
+ var _a, _b;
151
+ if (idx <= f.lastEmittedIdx)
152
+ return; // already emitted (e.g. SQL block range)
153
+ flushHiddenBefore(f, idx);
154
+ const text = (_a = t.text) !== null && _a !== void 0 ? _a : '';
155
+ // ---- Verbatim regions: SQL strings and block annotations ----
156
+ // We don't own a SQL formatter. Annotation indentation is significant.
157
+ if (t.type === tokens_1.L.SQL_BEGIN) {
158
+ const endIdx = (0, tokens_1.findMatching)(f.tokens, idx, tokens_1.L.SQL_BEGIN, tokens_1.L.SQL_END);
159
+ const stop = f.tokens[endIdx].stopIndex;
160
+ f.o.space();
161
+ f.o.text(f.src.substring(t.startIndex, stop + 1));
162
+ note(f, tokens_1.L.SQL_END, endIdx, f.tokens[endIdx]);
163
+ return;
164
+ }
165
+ if (t.type === tokens_1.L.BLOCK_ANNOTATION_BEGIN ||
166
+ t.type === tokens_1.L.DOC_BLOCK_ANNOTATION_BEGIN) {
167
+ const endIdx = (0, tokens_1.findMatching)(f.tokens, idx, t.type, tokens_1.L.BLOCK_ANNOTATION_END);
168
+ const stop = f.tokens[endIdx].stopIndex;
169
+ if (f.o.indent === 0)
170
+ startStatementLine(f);
171
+ else
172
+ f.o.nl();
173
+ f.o.text(f.src.substring(t.startIndex, stop + 1));
174
+ f.o.nl();
175
+ note(f, tokens_1.L.BLOCK_ANNOTATION_END, endIdx, f.tokens[endIdx]);
176
+ return;
177
+ }
178
+ // ---- Single-line annotations on their own line ----
179
+ if (t.type === tokens_1.L.ANNOTATION || t.type === tokens_1.L.DOC_ANNOTATION) {
180
+ if (f.o.indent === 0)
181
+ startStatementLine(f);
182
+ else
183
+ f.o.nl();
184
+ f.o.text(text.replace(/\s+$/, ''));
185
+ f.o.nl();
186
+ note(f, t.type, idx, t);
187
+ return;
188
+ }
189
+ // ---- Curly braces: indent in/out around block bodies ----
190
+ if (t.type === tokens_1.L.OCURLY) {
191
+ f.o.space();
192
+ f.o.text('{');
193
+ f.o.indent++;
194
+ f.o.nl();
195
+ note(f, t.type, idx, t);
196
+ return;
197
+ }
198
+ if (t.type === tokens_1.L.CCURLY) {
199
+ f.o.indent = Math.max(0, f.o.indent - 1);
200
+ f.o.nl();
201
+ f.o.text('}');
202
+ if (f.o.indent === 0)
203
+ f.needBlank = true;
204
+ note(f, t.type, idx, t);
205
+ return;
206
+ }
207
+ // ---- Statement separators ----
208
+ // `;` in wrapped form is dropped — newlines do the job. (Inline `;` appears
209
+ // via renderItemInline, not here.)
210
+ if (t.type === tokens_1.L.SEMI) {
211
+ f.o.trimTrailingSpace();
212
+ f.o.nl();
213
+ if (f.o.indent === 0)
214
+ f.needBlank = true;
215
+ note(f, t.type, idx, t);
216
+ return;
217
+ }
218
+ // ---- Commas ----
219
+ // At top level (parenDepth==0) → newline. Inside parens that the wrap logic
220
+ // flagged as multi-line → newline. Otherwise inline (just space).
221
+ if (t.type === tokens_1.L.COMMA) {
222
+ f.o.trimTrailingSpace();
223
+ f.o.text(',');
224
+ const innerBreaks = f.parenBreaks.length > 0 && f.parenBreaks[f.parenBreaks.length - 1];
225
+ if (f.parenDepth === 0 || innerBreaks)
226
+ f.o.nl();
227
+ note(f, t.type, idx, t);
228
+ return;
229
+ }
230
+ // ---- Open paren / bracket: decide call-hug vs grouping, decide wrap ----
231
+ if (t.type === tokens_1.L.OPAREN || t.type === tokens_1.L.OBRACK) {
232
+ const action = (0, tokens_1.leadingAction)(f.lastEmittedType, t.type);
233
+ if (action === 'space')
234
+ f.o.space();
235
+ f.o.text(text);
236
+ // Decide whether the contents will exceed the line budget when laid out
237
+ // inline. Break only if there's somewhere useful to break:
238
+ // - call/subscript parens (action='hug'): must have ≥ 2 args (commas at
239
+ // this depth);
240
+ // - grouping parens (action='space'): any overflow — content's own
241
+ // rules will wrap.
242
+ const closeType = t.type === tokens_1.L.OPAREN ? tokens_1.L.CPAREN : tokens_1.L.CBRACK;
243
+ const matchIdx = (0, tokens_1.findMatching)(f.tokens, idx, t.type, closeType);
244
+ const inlineLen = approxInlineSpan(f, idx, matchIdx);
245
+ const wouldOverflow = f.o.lineLengthSoFar() + inlineLen > tokens_1.LINE_BUDGET;
246
+ const hasArgCommas = hasCommaAtDepth1(f, idx, matchIdx);
247
+ const isCall = action === 'hug';
248
+ const willBreak = wouldOverflow && (hasArgCommas || !isCall);
249
+ f.parenBreaks.push(willBreak);
250
+ f.parenDepth++;
251
+ if (willBreak) {
252
+ f.o.indent++;
253
+ f.o.nl();
254
+ }
255
+ note(f, t.type, idx, t);
256
+ return;
257
+ }
258
+ if (t.type === tokens_1.L.CPAREN || t.type === tokens_1.L.CBRACK) {
259
+ const wasBreak = (_b = f.parenBreaks.pop()) !== null && _b !== void 0 ? _b : false;
260
+ if (wasBreak) {
261
+ f.o.indent = Math.max(0, f.o.indent - 1);
262
+ f.o.nl();
263
+ }
264
+ else {
265
+ f.o.trimTrailingSpace();
266
+ }
267
+ f.o.text(text);
268
+ f.parenDepth = Math.max(0, f.parenDepth - 1);
269
+ note(f, t.type, idx, t);
270
+ return;
271
+ }
272
+ // ---- Section keyword fallback (no explicit handler took it) ----
273
+ // Inside a brace block, force a fresh line. Keeps v1-style readable output
274
+ // even for sections we don't yet handle.
275
+ if (tokens_1.SECTION_TOKENS.has(t.type) && f.o.indent > 0) {
276
+ f.o.nl();
277
+ f.o.text(text.replace(/\s+/g, ''));
278
+ note(f, t.type, idx, t);
279
+ return;
280
+ }
281
+ // ---- Top-level statement starter ----
282
+ if (tokens_1.TOP_LEVEL_STARTERS.has(t.type) &&
283
+ f.o.indent === 0 &&
284
+ f.parenDepth === 0) {
285
+ startStatementLine(f);
286
+ f.o.text(text.replace(/\s+/g, ''));
287
+ note(f, t.type, idx, t);
288
+ return;
289
+ }
290
+ // ---- Default: identifier / literal / keyword / DOT / COLON / TRIPLECOLON
291
+ // / binary op. Leading separator from the classifier; binary ops also
292
+ // get a trailing space.
293
+ const action = (0, tokens_1.leadingAction)(f.lastEmittedType, t.type);
294
+ if (action === 'glue')
295
+ f.o.trimTrailingSpace();
296
+ else if (action === 'space')
297
+ f.o.space();
298
+ // 'hug' — emit nothing before
299
+ f.o.text(text);
300
+ if (tokens_1.BINARY_OPS.has(t.type))
301
+ f.o.space();
302
+ note(f, t.type, idx, t);
303
+ }
304
+ // Emit each visible token in [fromIdx, toIdx] via the leaf walker.
305
+ function formatTokenRange(f, fromIdx, toIdx) {
306
+ for (let i = fromIdx; i <= toIdx; i++) {
307
+ const t = f.tokens[i];
308
+ if (t.channel !== antlr4ts_1.Token.HIDDEN_CHANNEL && t.type !== antlr4ts_1.Token.EOF) {
309
+ emitVisibleToken(f, t, i);
310
+ }
311
+ }
312
+ }
313
+ //# sourceMappingURL=leaf.js.map
@@ -0,0 +1,12 @@
1
+ export declare class Out {
2
+ buf: string;
3
+ indent: number;
4
+ text(s: string): void;
5
+ space(): void;
6
+ nl(): void;
7
+ blank(): void;
8
+ trimTrailingSpace(): void;
9
+ trimTrailingNewlines(): void;
10
+ lineLengthSoFar(): number;
11
+ toString(): string;
12
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.Out = void 0;
8
+ const tokens_1 = require("./tokens");
9
+ // Append-only buffer with helpers for indentation, single-space coalescing,
10
+ // and newlines. Knows nothing about Malloy; the formatting rules call into it.
11
+ class Out {
12
+ constructor() {
13
+ this.buf = '';
14
+ this.indent = 0;
15
+ }
16
+ // Append text. If the buffer ended with a newline, prepend the current
17
+ // indent first so the new text starts at the right column.
18
+ text(s) {
19
+ if (this.buf.endsWith('\n'))
20
+ this.buf += tokens_1.INDENT_STR.repeat(this.indent);
21
+ this.buf += s;
22
+ }
23
+ // Append at most one space. No-op at start of buffer, after newline, or
24
+ // after `(`, `[`, `.` (so `f(x` stays glued).
25
+ space() {
26
+ if (this.buf.length === 0)
27
+ return;
28
+ const last = this.buf[this.buf.length - 1];
29
+ if (last === ' ' ||
30
+ last === '\n' ||
31
+ last === '(' ||
32
+ last === '[' ||
33
+ last === '.')
34
+ return;
35
+ this.buf += ' ';
36
+ }
37
+ // Force the next emit onto a new line. Trailing spaces are stripped.
38
+ nl() {
39
+ if (this.buf.length === 0)
40
+ return;
41
+ this.buf = this.buf.replace(/ +$/, '');
42
+ if (!this.buf.endsWith('\n'))
43
+ this.buf += '\n';
44
+ }
45
+ // Force a blank line before the next emit. No-op at start of buffer.
46
+ blank() {
47
+ if (this.buf.length === 0)
48
+ return;
49
+ this.nl();
50
+ if (!this.buf.endsWith('\n\n'))
51
+ this.buf += '\n';
52
+ }
53
+ trimTrailingSpace() {
54
+ this.buf = this.buf.replace(/ +$/, '');
55
+ }
56
+ trimTrailingNewlines() {
57
+ this.buf = this.buf.replace(/\n+$/, '');
58
+ }
59
+ // The column the next emit will land at. When the buffer ends with a
60
+ // newline the indent isn't yet in `buf`, so we have to add the pending
61
+ // indent width to predict where the next text will appear.
62
+ lineLengthSoFar() {
63
+ if (this.buf.length === 0 || this.buf.endsWith('\n')) {
64
+ return this.indent * tokens_1.INDENT_STR.length;
65
+ }
66
+ const lastNl = this.buf.lastIndexOf('\n');
67
+ return this.buf.length - (lastNl + 1);
68
+ }
69
+ toString() {
70
+ return this.buf.replace(/\n*$/, '\n');
71
+ }
72
+ }
73
+ exports.Out = Out;
74
+ //# sourceMappingURL=out.js.map
@@ -0,0 +1,5 @@
1
+ import * as parser from '../lib/Malloy/MalloyParser';
2
+ import type { Formatter } from './formatter';
3
+ export declare function formatPickStatement(f: Formatter, ctx: parser.PickStatementContext): void;
4
+ export declare function formatPick(f: Formatter, ctx: parser.PickContext): void;
5
+ export declare function formatCaseStatement(f: Formatter, ctx: parser.CaseStatementContext): void;