@malloydata/malloy 0.0.385 → 0.0.387
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/internal.d.ts +2 -0
- package/dist/internal.js +3 -1
- package/dist/lang/prettify/binary-chain.d.ts +3 -0
- package/dist/lang/prettify/binary-chain.js +65 -0
- package/dist/lang/prettify/block-body.d.ts +4 -0
- package/dist/lang/prettify/block-body.js +87 -0
- package/dist/lang/prettify/error-listener.d.ts +6 -0
- package/dist/lang/prettify/error-listener.js +19 -0
- package/dist/lang/prettify/field-properties.d.ts +3 -0
- package/dist/lang/prettify/field-properties.js +57 -0
- package/dist/lang/prettify/formatter.d.ts +17 -0
- package/dist/lang/prettify/formatter.js +150 -0
- package/dist/lang/prettify/import-select.d.ts +3 -0
- package/dist/lang/prettify/import-select.js +88 -0
- package/dist/lang/prettify/index.d.ts +19 -0
- package/dist/lang/prettify/index.js +163 -0
- package/dist/lang/prettify/inline-renderer.d.ts +3 -0
- package/dist/lang/prettify/inline-renderer.js +101 -0
- package/dist/lang/prettify/leaf.d.ts +9 -0
- package/dist/lang/prettify/leaf.js +340 -0
- package/dist/lang/prettify/out.d.ts +12 -0
- package/dist/lang/prettify/out.js +74 -0
- package/dist/lang/prettify/pick-case.d.ts +5 -0
- package/dist/lang/prettify/pick-case.js +222 -0
- package/dist/lang/prettify/rules.d.ts +13 -0
- package/dist/lang/prettify/rules.js +111 -0
- package/dist/lang/prettify/sections.d.ts +4 -0
- package/dist/lang/prettify/sections.js +380 -0
- package/dist/lang/prettify/tokens.d.ts +13 -0
- package/dist/lang/prettify/tokens.js +185 -0
- package/dist/lang/prettify/types.d.ts +9 -0
- package/dist/lang/prettify/types.js +7 -0
- package/dist/lang/run-malloy-parser.d.ts +23 -0
- package/dist/lang/run-malloy-parser.js +32 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/dist/internal.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { mkArrayDef, mkArrayTypeDef, mkFieldDef, mkModelDef, mkQuerySourceDef, mkSQLSourceDef, mkTableSourceDef, pathToKey, } from './model';
|
|
2
2
|
export { TinyParseError, TinyParser } from './dialect/tiny_parser';
|
|
3
3
|
export type { TinyToken } from './dialect/tiny_parser';
|
|
4
|
+
export { prettify } from './lang/prettify';
|
|
5
|
+
export type { PrettifyResult, PrettifyError } from './lang/prettify';
|
package/dist/internal.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.TinyParser = exports.TinyParseError = exports.pathToKey = exports.mkTableSourceDef = exports.mkSQLSourceDef = exports.mkQuerySourceDef = exports.mkModelDef = exports.mkFieldDef = exports.mkArrayTypeDef = exports.mkArrayDef = void 0;
|
|
7
|
+
exports.prettify = exports.TinyParser = exports.TinyParseError = exports.pathToKey = exports.mkTableSourceDef = exports.mkSQLSourceDef = exports.mkQuerySourceDef = exports.mkModelDef = exports.mkFieldDef = exports.mkArrayTypeDef = exports.mkArrayDef = void 0;
|
|
8
8
|
// Unstable implementation-facing exports for Malloy packages, tests, and
|
|
9
9
|
// advanced integrations. Do not treat this surface as public API.
|
|
10
10
|
var model_1 = require("./model");
|
|
@@ -19,4 +19,6 @@ Object.defineProperty(exports, "pathToKey", { enumerable: true, get: function ()
|
|
|
19
19
|
var tiny_parser_1 = require("./dialect/tiny_parser");
|
|
20
20
|
Object.defineProperty(exports, "TinyParseError", { enumerable: true, get: function () { return tiny_parser_1.TinyParseError; } });
|
|
21
21
|
Object.defineProperty(exports, "TinyParser", { enumerable: true, get: function () { return tiny_parser_1.TinyParser; } });
|
|
22
|
+
var prettify_1 = require("./lang/prettify");
|
|
23
|
+
Object.defineProperty(exports, "prettify", { enumerable: true, get: function () { return prettify_1.prettify; } });
|
|
22
24
|
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* RULE: BINARY CHAIN — formatBinaryChain
|
|
7
|
+
*
|
|
8
|
+
* Handles `and`/`or`/`??`/`+`/`-` chains. The grammar is left-recursive, so a
|
|
9
|
+
* chain `a + b + c` parses as `((a + b) + c)`. Only the OUTERMOST chain
|
|
10
|
+
* context emits; inner same-class contexts fall through to default recursion
|
|
11
|
+
* so the outer can collect all operands.
|
|
12
|
+
*
|
|
13
|
+
* Inline if it fits. Otherwise: first operand inline; each subsequent
|
|
14
|
+
* operator+operand on its own line at +1 indent (leading-operator style).
|
|
15
|
+
*
|
|
16
|
+
* We deliberately do NOT break at comparison operators — see prettify header.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.formatBinaryChain = formatBinaryChain;
|
|
20
|
+
const antlr4ts_1 = require("antlr4ts");
|
|
21
|
+
const tree_1 = require("antlr4ts/tree");
|
|
22
|
+
const tokens_1 = require("./tokens");
|
|
23
|
+
const leaf_1 = require("./leaf");
|
|
24
|
+
function formatBinaryChain(f, ctx) {
|
|
25
|
+
// Same chain class as our parent? Then we're an inner node of the chain —
|
|
26
|
+
// let the outermost one collect all operands and emit.
|
|
27
|
+
if (ctx.parent && ctx.parent.constructor === ctx.constructor) {
|
|
28
|
+
for (let i = 0; i < ctx.childCount; i++)
|
|
29
|
+
f.format(ctx.getChild(i));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const operands = [];
|
|
33
|
+
const operators = [];
|
|
34
|
+
const collect = (n) => {
|
|
35
|
+
if (n instanceof antlr4ts_1.ParserRuleContext && n.constructor === ctx.constructor) {
|
|
36
|
+
// Inner same-class chain node. Grammar guarantees getChild(1) is a
|
|
37
|
+
// TerminalNode (the operator); the guard makes that explicit without
|
|
38
|
+
// a cast.
|
|
39
|
+
collect(n.getChild(0));
|
|
40
|
+
const op = n.getChild(1);
|
|
41
|
+
if (op instanceof tree_1.TerminalNode)
|
|
42
|
+
operators.push(op);
|
|
43
|
+
operands.push(n.getChild(2));
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
operands.push(n);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
collect(ctx);
|
|
50
|
+
const inlineLen = (0, leaf_1.approxInlineSpan)(f, ctx._start.tokenIndex, ctx._stop.tokenIndex);
|
|
51
|
+
if (f.o.lineLengthSoFar() + 1 + inlineLen <= tokens_1.LINE_BUDGET) {
|
|
52
|
+
for (let i = 0; i < ctx.childCount; i++)
|
|
53
|
+
f.format(ctx.getChild(i));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
f.format(operands[0]);
|
|
57
|
+
f.o.indent++;
|
|
58
|
+
for (let i = 0; i < operators.length; i++) {
|
|
59
|
+
f.o.nl();
|
|
60
|
+
f.format(operators[i]);
|
|
61
|
+
f.format(operands[i + 1]);
|
|
62
|
+
}
|
|
63
|
+
f.o.indent--;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=binary-chain.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* RULE: BLOCK BODY
|
|
7
|
+
*
|
|
8
|
+
* A `{ … }` body containing statements (extend body, view body, etc.). Walks
|
|
9
|
+
* children; between adjacent statements:
|
|
10
|
+
* - `view:` definitions always get a blank line before them (and after
|
|
11
|
+
* the previous one), regardless of whether the source had a blank or
|
|
12
|
+
* what kind preceded — view definitions read as their own sections.
|
|
13
|
+
* - For other kinds: preserve a single user-supplied blank line only if
|
|
14
|
+
* the kinds differ. Same-kind adjacent statements (consecutive
|
|
15
|
+
* dimensions, measures, etc.) never get a blank.
|
|
16
|
+
*
|
|
17
|
+
* Also: top-level body — forces a blank line before each statement after the
|
|
18
|
+
* first, regardless of source spacing (top-level statements should breathe).
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.formatTopLevel = formatTopLevel;
|
|
22
|
+
exports.formatBlockBody = formatBlockBody;
|
|
23
|
+
const antlr4ts_1 = require("antlr4ts");
|
|
24
|
+
const tree_1 = require("antlr4ts/tree");
|
|
25
|
+
const rules_1 = require("./rules");
|
|
26
|
+
const tokens_1 = require("./tokens");
|
|
27
|
+
const leaf_1 = require("./leaf");
|
|
28
|
+
function statementKind(ctx) {
|
|
29
|
+
for (const r of rules_1.STATEMENT_KIND_BY_CTX) {
|
|
30
|
+
if (ctx instanceof r.ctxClass)
|
|
31
|
+
return r.kind;
|
|
32
|
+
}
|
|
33
|
+
return ctx.constructor.name;
|
|
34
|
+
}
|
|
35
|
+
function formatTopLevel(f, ctx) {
|
|
36
|
+
let emittedFirst = false;
|
|
37
|
+
for (let i = 0; i < ctx.childCount; i++) {
|
|
38
|
+
const c = ctx.getChild(i);
|
|
39
|
+
if (c instanceof tree_1.TerminalNode) {
|
|
40
|
+
const tok = c.symbol;
|
|
41
|
+
if (tok.type !== antlr4ts_1.Token.EOF)
|
|
42
|
+
(0, leaf_1.emitVisibleToken)(f, tok, tok.tokenIndex);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (c instanceof antlr4ts_1.ParserRuleContext) {
|
|
46
|
+
if (emittedFirst)
|
|
47
|
+
f.needBlank = true;
|
|
48
|
+
f.format(c);
|
|
49
|
+
emittedFirst = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function formatBlockBody(f, ctx) {
|
|
54
|
+
let lastChild = null;
|
|
55
|
+
let lastChildEndLine = 0;
|
|
56
|
+
for (let i = 0; i < ctx.childCount; i++) {
|
|
57
|
+
const c = ctx.getChild(i);
|
|
58
|
+
if (c instanceof tree_1.TerminalNode) {
|
|
59
|
+
// OCURLY / CCURLY / SEMI — let the leaf walker handle them.
|
|
60
|
+
const tok = c.symbol;
|
|
61
|
+
if (tok.type !== antlr4ts_1.Token.EOF)
|
|
62
|
+
(0, leaf_1.emitVisibleToken)(f, tok, tok.tokenIndex);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (c instanceof antlr4ts_1.ParserRuleContext) {
|
|
66
|
+
if (lastChild !== null) {
|
|
67
|
+
const userHadBlank = c._start.line - lastChildEndLine > 1;
|
|
68
|
+
const lastKind = statementKind(lastChild);
|
|
69
|
+
const curKind = statementKind(c);
|
|
70
|
+
const sameKind = lastKind === curKind;
|
|
71
|
+
// `view:` definitions always breathe — blank line above each one
|
|
72
|
+
// (and after the previous one) regardless of the user's source
|
|
73
|
+
// spacing or what kind preceded.
|
|
74
|
+
if (curKind === 'view' || lastKind === 'view') {
|
|
75
|
+
f.o.blank();
|
|
76
|
+
}
|
|
77
|
+
else if (userHadBlank && !sameKind) {
|
|
78
|
+
f.o.blank();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
f.format(c);
|
|
82
|
+
lastChild = c;
|
|
83
|
+
lastChildEndLine = (0, tokens_1.endLineOf)(c._stop);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=block-body.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ANTLRErrorListener, RecognitionException, Recognizer } from 'antlr4ts';
|
|
2
|
+
import type { PrettifyError } from './types';
|
|
3
|
+
export declare class CollectingErrorListener implements ANTLRErrorListener<any> {
|
|
4
|
+
errors: PrettifyError[];
|
|
5
|
+
syntaxError<T>(_recognizer: Recognizer<T, any>, _offendingSymbol: T | undefined, line: number, charPositionInLine: number, msg: string, _e: RecognitionException | undefined): void;
|
|
6
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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.CollectingErrorListener = void 0;
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
9
|
+
class CollectingErrorListener {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.errors = [];
|
|
12
|
+
}
|
|
13
|
+
syntaxError(_recognizer, _offendingSymbol, line, charPositionInLine, msg, _e) {
|
|
14
|
+
this.errors.push({ message: msg, line, column: charPositionInLine });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.CollectingErrorListener = CollectingErrorListener;
|
|
18
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
19
|
+
//# sourceMappingURL=error-listener.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* RULE: POSTFIX `{…}` — formatFieldProperties
|
|
7
|
+
*
|
|
8
|
+
* `expr { kw: ... }` — filter shortcut and friends. Inline if it fits;
|
|
9
|
+
* otherwise emit as a block with each inner statement on its own line. Inner
|
|
10
|
+
* statements are rendered atomically via formatTokenRange (no recursive
|
|
11
|
+
* section-list rewriting): they're part of the expression.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.formatFieldProperties = formatFieldProperties;
|
|
15
|
+
const antlr4ts_1 = require("antlr4ts");
|
|
16
|
+
const tokens_1 = require("./tokens");
|
|
17
|
+
const leaf_1 = require("./leaf");
|
|
18
|
+
const inline_renderer_1 = require("./inline-renderer");
|
|
19
|
+
function formatFieldProperties(f, ctx) {
|
|
20
|
+
const startIdx = ctx._start.tokenIndex;
|
|
21
|
+
const stopIdx = ctx._stop.tokenIndex;
|
|
22
|
+
const hasComments = (0, leaf_1.hasCommentsInRange)(f, startIdx, stopIdx);
|
|
23
|
+
if (!hasComments) {
|
|
24
|
+
const inline = (0, inline_renderer_1.renderItemInline)(f, ctx);
|
|
25
|
+
if (f.o.lineLengthSoFar() + 1 + inline.length <= tokens_1.LINE_BUDGET) {
|
|
26
|
+
f.o.space();
|
|
27
|
+
f.o.text(inline);
|
|
28
|
+
(0, leaf_1.note)(f, tokens_1.L.CCURLY, stopIdx, ctx._stop);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Wrapped form. Each inner statement runs through the leaf walker
|
|
33
|
+
// (formatTokenRange) so comments inside it are preserved naturally.
|
|
34
|
+
f.o.space();
|
|
35
|
+
f.o.text('{');
|
|
36
|
+
f.o.indent++;
|
|
37
|
+
// Advance past the OCURLY ourselves so flushHiddenBefore for the first inner
|
|
38
|
+
// statement doesn't try to re-emit it.
|
|
39
|
+
f.lastEmittedIdx = startIdx;
|
|
40
|
+
for (let i = 0; i < ctx.childCount; i++) {
|
|
41
|
+
const c = ctx.getChild(i);
|
|
42
|
+
// Skip OCURLY / CCURLY / SEMI; only inner statement contexts get walked.
|
|
43
|
+
if (!(c instanceof antlr4ts_1.ParserRuleContext))
|
|
44
|
+
continue;
|
|
45
|
+
f.o.nl();
|
|
46
|
+
(0, leaf_1.formatTokenRange)(f, c._start.tokenIndex, c._stop.tokenIndex);
|
|
47
|
+
}
|
|
48
|
+
// Flush any tail hidden tokens between the last inner statement and the
|
|
49
|
+
// closing `}` so trailing comments emit at the inner indent rather than
|
|
50
|
+
// disappearing.
|
|
51
|
+
(0, leaf_1.flushHiddenBefore)(f, stopIdx);
|
|
52
|
+
f.o.indent--;
|
|
53
|
+
f.o.nl();
|
|
54
|
+
f.o.text('}');
|
|
55
|
+
(0, leaf_1.note)(f, tokens_1.L.CCURLY, stopIdx, ctx._stop);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=field-properties.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Token } from 'antlr4ts';
|
|
2
|
+
import type { ParseTree } from 'antlr4ts/tree';
|
|
3
|
+
import { Out } from './out';
|
|
4
|
+
export declare class Formatter {
|
|
5
|
+
readonly src: string;
|
|
6
|
+
readonly tokens: Token[];
|
|
7
|
+
o: Out;
|
|
8
|
+
lastEmittedIdx: number;
|
|
9
|
+
lastEmittedType: number | null;
|
|
10
|
+
prevTokenEndLine: number;
|
|
11
|
+
needBlank: boolean;
|
|
12
|
+
parenDepth: number;
|
|
13
|
+
parenBreaks: boolean[];
|
|
14
|
+
private rootFormatted;
|
|
15
|
+
constructor(src: string, tokens: Token[]);
|
|
16
|
+
format(node: ParseTree): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Formatter: per-format-call state container plus the parse-tree dispatcher.
|
|
7
|
+
*
|
|
8
|
+
* State (Out buffer, last-emitted token tracking, paren-depth stack) is
|
|
9
|
+
* mutable and read/written directly by the per-rule free functions in sibling
|
|
10
|
+
* modules. The dispatcher is the only method on the class — it routes each
|
|
11
|
+
* parse-tree node to the appropriate per-rule formatter, falling back to
|
|
12
|
+
* left-to-right child recursion.
|
|
13
|
+
*
|
|
14
|
+
* The class itself is not exported beyond ./index, so its fields being
|
|
15
|
+
* "package-public" is hygiene only — no external API leakage.
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.Formatter = void 0;
|
|
52
|
+
const antlr4ts_1 = require("antlr4ts");
|
|
53
|
+
const tree_1 = require("antlr4ts/tree");
|
|
54
|
+
const parser = __importStar(require("../lib/Malloy/MalloyParser"));
|
|
55
|
+
const out_1 = require("./out");
|
|
56
|
+
const rules_1 = require("./rules");
|
|
57
|
+
const leaf_1 = require("./leaf");
|
|
58
|
+
const block_body_1 = require("./block-body");
|
|
59
|
+
const sections_1 = require("./sections");
|
|
60
|
+
const field_properties_1 = require("./field-properties");
|
|
61
|
+
const pick_case_1 = require("./pick-case");
|
|
62
|
+
const binary_chain_1 = require("./binary-chain");
|
|
63
|
+
const import_select_1 = require("./import-select");
|
|
64
|
+
class Formatter {
|
|
65
|
+
constructor(src, tokens) {
|
|
66
|
+
this.src = src;
|
|
67
|
+
this.tokens = tokens;
|
|
68
|
+
this.o = new out_1.Out();
|
|
69
|
+
// -- Per-token state (updated by `note(f, ...)` after every token emit) --
|
|
70
|
+
// Index of the last token (visible or implicitly skipped) we've accounted
|
|
71
|
+
// for. flushHiddenBefore won't re-emit anything at or before this index.
|
|
72
|
+
this.lastEmittedIdx = -1;
|
|
73
|
+
// Type of the last visible token emitted. Drives spacing decisions
|
|
74
|
+
// (e.g. CALL_HUG_AFTER membership for `(`).
|
|
75
|
+
this.lastEmittedType = null;
|
|
76
|
+
// 1-based line in the SOURCE where the last emitted token ended. Used to
|
|
77
|
+
// distinguish trailing-comments (same line) from leading-comments (different
|
|
78
|
+
// line).
|
|
79
|
+
this.prevTokenEndLine = 0;
|
|
80
|
+
// After end-of-top-level-statement, the next statement-starter gets a blank
|
|
81
|
+
// line. Consumed once, then reset.
|
|
82
|
+
this.needBlank = false;
|
|
83
|
+
// -- Paren-pair state --
|
|
84
|
+
this.parenDepth = 0;
|
|
85
|
+
// For each open paren-pair: did we choose to break args/content across
|
|
86
|
+
// lines? Stack matches parenDepth.
|
|
87
|
+
this.parenBreaks = [];
|
|
88
|
+
// Set when format() is invoked at the top level (a MalloyDocument). Guards
|
|
89
|
+
// against accidental reuse of a Formatter instance — the Out buffer
|
|
90
|
+
// accumulates and would emit garbage on a second call. Construct a fresh
|
|
91
|
+
// Formatter per top-level call.
|
|
92
|
+
this.rootFormatted = false;
|
|
93
|
+
}
|
|
94
|
+
format(node) {
|
|
95
|
+
if (node instanceof tree_1.TerminalNode) {
|
|
96
|
+
const tok = node.symbol;
|
|
97
|
+
if (tok.type !== antlr4ts_1.Token.EOF)
|
|
98
|
+
(0, leaf_1.emitVisibleToken)(this, tok, tok.tokenIndex);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!(node instanceof antlr4ts_1.ParserRuleContext))
|
|
102
|
+
return;
|
|
103
|
+
// RULE: TOP-LEVEL BODY — one blank line between adjacent statements.
|
|
104
|
+
if (node instanceof parser.MalloyDocumentContext) {
|
|
105
|
+
if (this.rootFormatted) {
|
|
106
|
+
throw new Error('Formatter is single-use; construct a new instance per top-level format call');
|
|
107
|
+
}
|
|
108
|
+
this.rootFormatted = true;
|
|
109
|
+
return (0, block_body_1.formatTopLevel)(this, node);
|
|
110
|
+
}
|
|
111
|
+
// RULE: POSTFIX `{…}` — filter shortcut etc.
|
|
112
|
+
if (node instanceof parser.FieldPropertiesContext) {
|
|
113
|
+
return (0, field_properties_1.formatFieldProperties)(this, node);
|
|
114
|
+
}
|
|
115
|
+
// RULE: BLOCK BODY — walk children, blank-lines between different kinds.
|
|
116
|
+
if (node instanceof parser.ExplorePropertiesContext ||
|
|
117
|
+
node instanceof parser.QueryPropertiesContext ||
|
|
118
|
+
node instanceof parser.QueryExtendStatementListContext) {
|
|
119
|
+
return (0, block_body_1.formatBlockBody)(this, node);
|
|
120
|
+
}
|
|
121
|
+
// RULE: SECTION-STATEMENT — table-driven dispatch.
|
|
122
|
+
for (const rule of rules_1.SECTION_STATEMENT_RULES) {
|
|
123
|
+
if (node instanceof rule.ctxClass) {
|
|
124
|
+
return (0, sections_1.formatSectionStatement)(this, node, rule);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// RULE: IMPORT SELECT — `import {a, b} from 'x'` stays compact.
|
|
128
|
+
if (node instanceof parser.ImportSelectContext) {
|
|
129
|
+
return (0, import_select_1.formatImportSelect)(this, node);
|
|
130
|
+
}
|
|
131
|
+
// RULE: PICK / CASE / BINARY CHAIN.
|
|
132
|
+
if (node instanceof parser.PickStatementContext)
|
|
133
|
+
return (0, pick_case_1.formatPickStatement)(this, node);
|
|
134
|
+
if (node instanceof parser.PickContext)
|
|
135
|
+
return (0, pick_case_1.formatPick)(this, node);
|
|
136
|
+
if (node instanceof parser.CaseStatementContext)
|
|
137
|
+
return (0, pick_case_1.formatCaseStatement)(this, node);
|
|
138
|
+
if (node instanceof parser.ExprLogicalAndContext ||
|
|
139
|
+
node instanceof parser.ExprLogicalOrContext ||
|
|
140
|
+
node instanceof parser.ExprCoalesceContext ||
|
|
141
|
+
node instanceof parser.ExprAddSubContext) {
|
|
142
|
+
return (0, binary_chain_1.formatBinaryChain)(this, node);
|
|
143
|
+
}
|
|
144
|
+
// Default: recurse on children left-to-right.
|
|
145
|
+
for (let i = 0; i < node.childCount; i++)
|
|
146
|
+
this.format(node.getChild(i));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
exports.Formatter = Formatter;
|
|
150
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* RULE: IMPORT SELECT — `import {a, b, c} from 'url'`
|
|
7
|
+
*
|
|
8
|
+
* The selection list is `{ id (IS id)? (, id (IS id)?)* }`. Inline if the
|
|
9
|
+
* whole brace-and-contents fits on the current line. Otherwise wrap with
|
|
10
|
+
* each item on its own line at +1 indent.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.formatImportSelect = formatImportSelect;
|
|
14
|
+
const tokens_1 = require("./tokens");
|
|
15
|
+
const leaf_1 = require("./leaf");
|
|
16
|
+
const inline_renderer_1 = require("./inline-renderer");
|
|
17
|
+
function formatImportSelect(f, ctx) {
|
|
18
|
+
// Flush hidden tokens between the previous emit (IMPORT) and our opener
|
|
19
|
+
// so a comment like `import /* tag */ {a} from 'x'` is preserved.
|
|
20
|
+
(0, leaf_1.flushHiddenBefore)(f, ctx._start.tokenIndex);
|
|
21
|
+
const items = ctx.importItem();
|
|
22
|
+
// Grammar puts FROM as the last token of importSelect: emit it ourselves
|
|
23
|
+
// so the trailing space and lastEmittedIdx land correctly.
|
|
24
|
+
const fromTok = ctx.FROM().symbol;
|
|
25
|
+
const fromIdx = fromTok.tokenIndex;
|
|
26
|
+
if (items.length === 0) {
|
|
27
|
+
f.o.space();
|
|
28
|
+
f.o.text('{} from');
|
|
29
|
+
(0, leaf_1.note)(f, tokens_1.L.FROM, fromIdx, fromTok);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const firstItem = items[0];
|
|
33
|
+
const lastItem = items[items.length - 1];
|
|
34
|
+
// Comments anywhere in the items' span (between items, inside an `as is`
|
|
35
|
+
// form, etc.) get stripped by renderItemInline. Fall back to a comment-
|
|
36
|
+
// safe wrap that emits each item via f.format — the leaf walker handles
|
|
37
|
+
// hidden-channel placement.
|
|
38
|
+
const itemsHaveComments = (0, leaf_1.hasCommentsInRange)(f, firstItem._start.tokenIndex, lastItem._stop.tokenIndex);
|
|
39
|
+
if (!itemsHaveComments) {
|
|
40
|
+
const itemStrs = items.map(it => (0, inline_renderer_1.renderItemInline)(f, it));
|
|
41
|
+
const inlineBody = '{' + itemStrs.join(', ') + '} from';
|
|
42
|
+
if (f.o.lineLengthSoFar() + 1 + inlineBody.length <= tokens_1.LINE_BUDGET) {
|
|
43
|
+
f.o.space();
|
|
44
|
+
f.o.text(inlineBody);
|
|
45
|
+
(0, leaf_1.note)(f, tokens_1.L.FROM, fromIdx, fromTok);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Wrap form (no comments): one item per line at +1 indent. Pre-rendered
|
|
49
|
+
// text is fine because renderItemInline saw no comments to drop.
|
|
50
|
+
f.o.space();
|
|
51
|
+
f.o.text('{');
|
|
52
|
+
f.o.indent++;
|
|
53
|
+
for (let i = 0; i < itemStrs.length; i++) {
|
|
54
|
+
f.o.nl();
|
|
55
|
+
f.o.text(itemStrs[i]);
|
|
56
|
+
if (i < itemStrs.length - 1)
|
|
57
|
+
f.o.text(',');
|
|
58
|
+
}
|
|
59
|
+
f.o.indent--;
|
|
60
|
+
f.o.nl();
|
|
61
|
+
f.o.text('} from');
|
|
62
|
+
(0, leaf_1.note)(f, tokens_1.L.FROM, fromIdx, fromTok);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Comment-safe wrap: each item emits via f.format so flushHiddenBefore
|
|
66
|
+
// can place its leading/inter-item comments correctly. Trailing `,` after
|
|
67
|
+
// each non-last item, leaf walker turns it into a newline at indent.
|
|
68
|
+
f.o.space();
|
|
69
|
+
f.o.text('{');
|
|
70
|
+
f.o.indent++;
|
|
71
|
+
// Advance past the OCURLY we just emitted manually so the first item's
|
|
72
|
+
// flushHiddenBefore doesn't try to re-emit it.
|
|
73
|
+
f.lastEmittedIdx = ctx._start.tokenIndex;
|
|
74
|
+
for (let i = 0; i < items.length; i++) {
|
|
75
|
+
(0, leaf_1.flushHiddenBefore)(f, items[i]._start.tokenIndex);
|
|
76
|
+
f.o.nl();
|
|
77
|
+
f.format(items[i]);
|
|
78
|
+
if (i < items.length - 1)
|
|
79
|
+
f.o.text(',');
|
|
80
|
+
}
|
|
81
|
+
// Catch any tail comments between the last item and the closing `}`.
|
|
82
|
+
(0, leaf_1.flushHiddenBefore)(f, fromIdx);
|
|
83
|
+
f.o.indent--;
|
|
84
|
+
f.o.nl();
|
|
85
|
+
f.o.text('} from');
|
|
86
|
+
(0, leaf_1.note)(f, tokens_1.L.FROM, fromIdx, fromTok);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=import-select.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PrettifyResult } from './types';
|
|
2
|
+
export type { PrettifyError, PrettifyResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Pretty-print a Malloy source string.
|
|
5
|
+
*
|
|
6
|
+
* **Experimental — this API may vanish or change at any time without notice.**
|
|
7
|
+
* It is exposed only via `@malloydata/malloy/internal` and is not covered by
|
|
8
|
+
* any compatibility commitment. Do not depend on it from anything you can't
|
|
9
|
+
* fix in a single PR.
|
|
10
|
+
*
|
|
11
|
+
* Parses the input, walks the parse tree, and emits a reformatted string.
|
|
12
|
+
*
|
|
13
|
+
* `errors` surfaces parse errors only (lexer + parser). Semantic / compile
|
|
14
|
+
* errors aren't checked here. If `errors.length > 0` you have a bigger problem
|
|
15
|
+
* than formatting — output is best-effort and not guaranteed to round-trip.
|
|
16
|
+
*
|
|
17
|
+
* @experimental
|
|
18
|
+
*/
|
|
19
|
+
export declare function prettify(src: string): PrettifyResult;
|