@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.
- package/dist/api/foundation/config_resolve.js +12 -20
- 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 +74 -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 +145 -0
- package/dist/lang/prettify/index.d.ts +19 -0
- package/dist/lang/prettify/index.js +139 -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 +313 -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 +103 -0
- package/dist/lang/prettify/sections.d.ts +4 -0
- package/dist/lang/prettify/sections.js +261 -0
- package/dist/lang/prettify/tokens.d.ts +13 -0
- package/dist/lang/prettify/tokens.js +160 -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
|
@@ -77,32 +77,24 @@ function extractCompiledConnections(node) {
|
|
|
77
77
|
return out;
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* POJO sets `includeDefaultConnections: true`. Property values
|
|
83
|
-
* reference-shaped defaults like DuckDB's
|
|
84
|
-
*
|
|
80
|
+
* For each registered connection type T, add a bare `{is: T}` compiled
|
|
81
|
+
* entry named T unless one already exists under that name. Only runs when
|
|
82
|
+
* the POJO sets `includeDefaultConnections: true`. Property values
|
|
83
|
+
* (including reference-shaped defaults like DuckDB's
|
|
84
|
+
* `{config: 'rootDirectory'}`) are filled in later by the async lookup
|
|
85
|
+
* resolver, not here.
|
|
85
86
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
87
|
+
* The skip is purely name-based: the `is` of a user entry is irrelevant.
|
|
88
|
+
* `{duckdb: {is: 'postgres'}}` shadows the duckdb phantom (slot taken);
|
|
89
|
+
* `{dankdb: {is: 'duckdb'}}` does not (slot `duckdb` is still free, and
|
|
90
|
+
* both end up reachable). This name-only rule is the contract hosts rely
|
|
91
|
+
* on — e.g. the VS Code connections sidebar advertises defaults by name,
|
|
92
|
+
* and the runtime must resolve them under those same names.
|
|
92
93
|
*
|
|
93
94
|
* Mutates `compiledConnections` in place.
|
|
94
95
|
*/
|
|
95
96
|
function fabricateMissingConnections(compiledConnections) {
|
|
96
|
-
const presentTypes = new Set();
|
|
97
|
-
for (const entry of Object.values(compiledConnections)) {
|
|
98
|
-
const isNode = entry.entries['is'];
|
|
99
|
-
if ((isNode === null || isNode === void 0 ? void 0 : isNode.kind) === 'value' && typeof isNode.value === 'string') {
|
|
100
|
-
presentTypes.add(isNode.value);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
97
|
for (const typeName of (0, registry_1.getRegisteredConnectionTypes)()) {
|
|
104
|
-
if (presentTypes.has(typeName))
|
|
105
|
-
continue;
|
|
106
98
|
if (compiledConnections[typeName])
|
|
107
99
|
continue;
|
|
108
100
|
compiledConnections[typeName] = {
|
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,74 @@
|
|
|
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, preserves a single user-supplied
|
|
10
|
+
* blank line *only if the kinds differ*. Same-kind adjacent statements never
|
|
11
|
+
* get a blank.
|
|
12
|
+
*
|
|
13
|
+
* Also: top-level body — forces a blank line before each statement after the
|
|
14
|
+
* first, regardless of source spacing (top-level statements should breathe).
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.formatTopLevel = formatTopLevel;
|
|
18
|
+
exports.formatBlockBody = formatBlockBody;
|
|
19
|
+
const antlr4ts_1 = require("antlr4ts");
|
|
20
|
+
const tree_1 = require("antlr4ts/tree");
|
|
21
|
+
const rules_1 = require("./rules");
|
|
22
|
+
const tokens_1 = require("./tokens");
|
|
23
|
+
const leaf_1 = require("./leaf");
|
|
24
|
+
function statementKind(ctx) {
|
|
25
|
+
for (const r of rules_1.STATEMENT_KIND_BY_CTX) {
|
|
26
|
+
if (ctx instanceof r.ctxClass)
|
|
27
|
+
return r.kind;
|
|
28
|
+
}
|
|
29
|
+
return ctx.constructor.name;
|
|
30
|
+
}
|
|
31
|
+
function formatTopLevel(f, ctx) {
|
|
32
|
+
let emittedFirst = false;
|
|
33
|
+
for (let i = 0; i < ctx.childCount; i++) {
|
|
34
|
+
const c = ctx.getChild(i);
|
|
35
|
+
if (c instanceof tree_1.TerminalNode) {
|
|
36
|
+
const tok = c.symbol;
|
|
37
|
+
if (tok.type !== antlr4ts_1.Token.EOF)
|
|
38
|
+
(0, leaf_1.emitVisibleToken)(f, tok, tok.tokenIndex);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (c instanceof antlr4ts_1.ParserRuleContext) {
|
|
42
|
+
if (emittedFirst)
|
|
43
|
+
f.needBlank = true;
|
|
44
|
+
f.format(c);
|
|
45
|
+
emittedFirst = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function formatBlockBody(f, ctx) {
|
|
50
|
+
let lastChild = null;
|
|
51
|
+
let lastChildEndLine = 0;
|
|
52
|
+
for (let i = 0; i < ctx.childCount; i++) {
|
|
53
|
+
const c = ctx.getChild(i);
|
|
54
|
+
if (c instanceof tree_1.TerminalNode) {
|
|
55
|
+
// OCURLY / CCURLY / SEMI — let the leaf walker handle them.
|
|
56
|
+
const tok = c.symbol;
|
|
57
|
+
if (tok.type !== antlr4ts_1.Token.EOF)
|
|
58
|
+
(0, leaf_1.emitVisibleToken)(f, tok, tok.tokenIndex);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (c instanceof antlr4ts_1.ParserRuleContext) {
|
|
62
|
+
if (lastChild !== null) {
|
|
63
|
+
const userHadBlank = c._start.line - lastChildEndLine > 1;
|
|
64
|
+
const sameKind = statementKind(lastChild) === statementKind(c);
|
|
65
|
+
if (userHadBlank && !sameKind)
|
|
66
|
+
f.o.blank();
|
|
67
|
+
}
|
|
68
|
+
f.format(c);
|
|
69
|
+
lastChild = c;
|
|
70
|
+
lastChildEndLine = (0, tokens_1.endLineOf)(c._stop);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# 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,145 @@
|
|
|
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
|
+
class Formatter {
|
|
64
|
+
constructor(src, tokens) {
|
|
65
|
+
this.src = src;
|
|
66
|
+
this.tokens = tokens;
|
|
67
|
+
this.o = new out_1.Out();
|
|
68
|
+
// -- Per-token state (updated by `note(f, ...)` after every token emit) --
|
|
69
|
+
// Index of the last token (visible or implicitly skipped) we've accounted
|
|
70
|
+
// for. flushHiddenBefore won't re-emit anything at or before this index.
|
|
71
|
+
this.lastEmittedIdx = -1;
|
|
72
|
+
// Type of the last visible token emitted. Drives spacing decisions
|
|
73
|
+
// (e.g. CALL_HUG_AFTER membership for `(`).
|
|
74
|
+
this.lastEmittedType = null;
|
|
75
|
+
// 1-based line in the SOURCE where the last emitted token ended. Used to
|
|
76
|
+
// distinguish trailing-comments (same line) from leading-comments (different
|
|
77
|
+
// line).
|
|
78
|
+
this.prevTokenEndLine = 0;
|
|
79
|
+
// After end-of-top-level-statement, the next statement-starter gets a blank
|
|
80
|
+
// line. Consumed once, then reset.
|
|
81
|
+
this.needBlank = false;
|
|
82
|
+
// -- Paren-pair state --
|
|
83
|
+
this.parenDepth = 0;
|
|
84
|
+
// For each open paren-pair: did we choose to break args/content across
|
|
85
|
+
// lines? Stack matches parenDepth.
|
|
86
|
+
this.parenBreaks = [];
|
|
87
|
+
// Set when format() is invoked at the top level (a MalloyDocument). Guards
|
|
88
|
+
// against accidental reuse of a Formatter instance — the Out buffer
|
|
89
|
+
// accumulates and would emit garbage on a second call. Construct a fresh
|
|
90
|
+
// Formatter per top-level call.
|
|
91
|
+
this.rootFormatted = false;
|
|
92
|
+
}
|
|
93
|
+
format(node) {
|
|
94
|
+
if (node instanceof tree_1.TerminalNode) {
|
|
95
|
+
const tok = node.symbol;
|
|
96
|
+
if (tok.type !== antlr4ts_1.Token.EOF)
|
|
97
|
+
(0, leaf_1.emitVisibleToken)(this, tok, tok.tokenIndex);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!(node instanceof antlr4ts_1.ParserRuleContext))
|
|
101
|
+
return;
|
|
102
|
+
// RULE: TOP-LEVEL BODY — one blank line between adjacent statements.
|
|
103
|
+
if (node instanceof parser.MalloyDocumentContext) {
|
|
104
|
+
if (this.rootFormatted) {
|
|
105
|
+
throw new Error('Formatter is single-use; construct a new instance per top-level format call');
|
|
106
|
+
}
|
|
107
|
+
this.rootFormatted = true;
|
|
108
|
+
return (0, block_body_1.formatTopLevel)(this, node);
|
|
109
|
+
}
|
|
110
|
+
// RULE: POSTFIX `{…}` — filter shortcut etc.
|
|
111
|
+
if (node instanceof parser.FieldPropertiesContext) {
|
|
112
|
+
return (0, field_properties_1.formatFieldProperties)(this, node);
|
|
113
|
+
}
|
|
114
|
+
// RULE: BLOCK BODY — walk children, blank-lines between different kinds.
|
|
115
|
+
if (node instanceof parser.ExplorePropertiesContext ||
|
|
116
|
+
node instanceof parser.QueryPropertiesContext ||
|
|
117
|
+
node instanceof parser.QueryExtendStatementListContext) {
|
|
118
|
+
return (0, block_body_1.formatBlockBody)(this, node);
|
|
119
|
+
}
|
|
120
|
+
// RULE: SECTION-STATEMENT — table-driven dispatch.
|
|
121
|
+
for (const rule of rules_1.SECTION_STATEMENT_RULES) {
|
|
122
|
+
if (node instanceof rule.ctxClass) {
|
|
123
|
+
return (0, sections_1.formatSectionStatement)(this, node, rule);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// RULE: PICK / CASE / BINARY CHAIN.
|
|
127
|
+
if (node instanceof parser.PickStatementContext)
|
|
128
|
+
return (0, pick_case_1.formatPickStatement)(this, node);
|
|
129
|
+
if (node instanceof parser.PickContext)
|
|
130
|
+
return (0, pick_case_1.formatPick)(this, node);
|
|
131
|
+
if (node instanceof parser.CaseStatementContext)
|
|
132
|
+
return (0, pick_case_1.formatCaseStatement)(this, node);
|
|
133
|
+
if (node instanceof parser.ExprLogicalAndContext ||
|
|
134
|
+
node instanceof parser.ExprLogicalOrContext ||
|
|
135
|
+
node instanceof parser.ExprCoalesceContext ||
|
|
136
|
+
node instanceof parser.ExprAddSubContext) {
|
|
137
|
+
return (0, binary_chain_1.formatBinaryChain)(this, node);
|
|
138
|
+
}
|
|
139
|
+
// Default: recurse on children left-to-right.
|
|
140
|
+
for (let i = 0; i < node.childCount; i++)
|
|
141
|
+
this.format(node.getChild(i));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.Formatter = Formatter;
|
|
145
|
+
//# sourceMappingURL=formatter.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;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* ============================================================================
|
|
7
|
+
* Malloy pretty-printer (experimental, /internal export — no stability promise)
|
|
8
|
+
* ============================================================================
|
|
9
|
+
*
|
|
10
|
+
* Architecture
|
|
11
|
+
* ------------
|
|
12
|
+
* 1. Lex + parse the input.
|
|
13
|
+
* 2. Walk the parse tree from `Formatter.format(node)`. The dispatcher routes
|
|
14
|
+
* each rule context to a per-rule free function in a sibling module;
|
|
15
|
+
* everything unhandled recurses to children, eventually reaching terminal
|
|
16
|
+
* tokens that emit through `emitVisibleToken` (the leaf).
|
|
17
|
+
* 3. The leaf walker handles per-token spacing/indentation/comments. It is
|
|
18
|
+
* v1's behaviour and is also the fallback when parsing fails.
|
|
19
|
+
*
|
|
20
|
+
* File layout
|
|
21
|
+
* -----------
|
|
22
|
+
* - ./out — Out buffer (indent, newlines, single-space coalescing).
|
|
23
|
+
* - ./tokens — LINE_BUDGET, INDENT_STR; classification sets
|
|
24
|
+
* (SECTION_TOKENS, BINARY_OPS, CALL_HUG_AFTER, etc.);
|
|
25
|
+
* findMatching, endLineOf.
|
|
26
|
+
* - ./rules — SECTION_STATEMENT_RULES + STATEMENT_KIND_BY_CTX.
|
|
27
|
+
* A maintainer adding a new section keyword lands here.
|
|
28
|
+
* - ./error-listener — CollectingErrorListener.
|
|
29
|
+
* - ./types — PrettifyError, PrettifyResult.
|
|
30
|
+
* - ./formatter — Formatter class (state + format() dispatcher).
|
|
31
|
+
* - ./leaf — emitVisibleToken + per-token state mutators
|
|
32
|
+
* (note, flushHiddenBefore, startStatementLine, …)
|
|
33
|
+
* and the small read-only helpers used by rule
|
|
34
|
+
* formatters (approxInlineSpan, hasCommentsInRange,
|
|
35
|
+
* formatTokenRange).
|
|
36
|
+
* - ./inline-renderer — renderItemInline (flat-string form for budget
|
|
37
|
+
* measurement and column alignment).
|
|
38
|
+
* - ./block-body — formatBlockBody, formatTopLevel.
|
|
39
|
+
* - ./sections — formatSectionStatement / formatSectionList.
|
|
40
|
+
* - ./field-properties — formatFieldProperties (postfix `{…}`).
|
|
41
|
+
* - ./pick-case — formatPickStatement, formatCaseStatement.
|
|
42
|
+
* - ./binary-chain — formatBinaryChain.
|
|
43
|
+
* - ./index (this) — prettify() entry point + type re-exports.
|
|
44
|
+
*
|
|
45
|
+
* Decisions worth knowing
|
|
46
|
+
* -----------------------
|
|
47
|
+
* - Comparison operators (`=`, `!=`, `<`, `>`, …) are kept glued to their
|
|
48
|
+
* operands. We only break chains at and/or/??/+/-. Justification: LHS/RHS
|
|
49
|
+
* of a comparison reads as one unit; breaking inside is more confusing
|
|
50
|
+
* than the line being long.
|
|
51
|
+
* - SQL strings (`"""…"""`, including `%{…}` malloy interpolations) and
|
|
52
|
+
* block annotations (`#" … "`) are emitted verbatim from source. We don't
|
|
53
|
+
* own a SQL formatter; annotation indentation is significant.
|
|
54
|
+
* - `;` is the compact-inline statement separator. Wrapped form drops it
|
|
55
|
+
* (newlines do the job); inline form keeps it.
|
|
56
|
+
* - `,` in section-list bare flow: intra-line yes, end-of-line never.
|
|
57
|
+
* - Single-arg function calls don't wrap (no point — nowhere useful to break).
|
|
58
|
+
* - `(` hugs only after a known-callable token (CALL_HUG_AFTER); after `is`,
|
|
59
|
+
* `as`, `extend`, `on`, `when`, etc. the `(` is grouping and gets a space.
|
|
60
|
+
*
|
|
61
|
+
* Adding a new section-statement
|
|
62
|
+
* ------------------------------
|
|
63
|
+
* Add a row to SECTION_STATEMENT_RULES in ./rules with the rule's context
|
|
64
|
+
* class, the keyword token type(s), the list-context accessor, and the
|
|
65
|
+
* item-kind tag. Add a corresponding entry to listItems() in ./sections.
|
|
66
|
+
*
|
|
67
|
+
* Note: section keywords NOT in the table fall through to the leaf walker
|
|
68
|
+
* (which produces correct-but-plain output). Add a row only when the default
|
|
69
|
+
* isn't good enough — flow-fill, alignment, or annotation handling.
|
|
70
|
+
*
|
|
71
|
+
* Inter-token spacing
|
|
72
|
+
* -------------------
|
|
73
|
+
* The classifier `leadingAction(prev, next)` in ./tokens is the single
|
|
74
|
+
* source of truth for what separator (glue, hug, or coalescing space) goes
|
|
75
|
+
* between two adjacent tokens. Both walkers — emitVisibleToken in ./leaf
|
|
76
|
+
* and renderItemInline in ./inline-renderer — consult it, so a change to
|
|
77
|
+
* `leadingAction` (e.g. adding a token type that hugs `(`) takes effect in
|
|
78
|
+
* both paths automatically. Walker-specific concerns (newlines, indent,
|
|
79
|
+
* paren-wrap decisions, compact-inline `, ` / `; `) live in the walker.
|
|
80
|
+
*/
|
|
81
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
82
|
+
exports.prettify = prettify;
|
|
83
|
+
const antlr4ts_1 = require("antlr4ts");
|
|
84
|
+
const run_malloy_parser_1 = require("../run-malloy-parser");
|
|
85
|
+
const error_listener_1 = require("./error-listener");
|
|
86
|
+
const formatter_1 = require("./formatter");
|
|
87
|
+
const leaf_1 = require("./leaf");
|
|
88
|
+
/**
|
|
89
|
+
* Pretty-print a Malloy source string.
|
|
90
|
+
*
|
|
91
|
+
* **Experimental — this API may vanish or change at any time without notice.**
|
|
92
|
+
* It is exposed only via `@malloydata/malloy/internal` and is not covered by
|
|
93
|
+
* any compatibility commitment. Do not depend on it from anything you can't
|
|
94
|
+
* fix in a single PR.
|
|
95
|
+
*
|
|
96
|
+
* Parses the input, walks the parse tree, and emits a reformatted string.
|
|
97
|
+
*
|
|
98
|
+
* `errors` surfaces parse errors only (lexer + parser). Semantic / compile
|
|
99
|
+
* errors aren't checked here. If `errors.length > 0` you have a bigger problem
|
|
100
|
+
* than formatting — output is best-effort and not guaranteed to round-trip.
|
|
101
|
+
*
|
|
102
|
+
* @experimental
|
|
103
|
+
*/
|
|
104
|
+
function prettify(src) {
|
|
105
|
+
const lexerErrors = new error_listener_1.CollectingErrorListener();
|
|
106
|
+
const parserErrors = new error_listener_1.CollectingErrorListener();
|
|
107
|
+
const { tokenStream, parser: malloyParser } = (0, run_malloy_parser_1.makeMalloyParser)(src, {
|
|
108
|
+
lexerErrorListener: lexerErrors,
|
|
109
|
+
parserErrorListener: parserErrors,
|
|
110
|
+
});
|
|
111
|
+
tokenStream.fill();
|
|
112
|
+
const tokens = tokenStream.getTokens();
|
|
113
|
+
let root = null;
|
|
114
|
+
try {
|
|
115
|
+
root = malloyParser.malloyDocument();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
root = null;
|
|
119
|
+
}
|
|
120
|
+
const f = new formatter_1.Formatter(src, tokens);
|
|
121
|
+
if (root) {
|
|
122
|
+
f.format(root);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Parse failed. Fall back to leaf-only emission so we still produce
|
|
126
|
+
// something reasonable.
|
|
127
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
128
|
+
const t = tokens[i];
|
|
129
|
+
if (t.channel !== antlr4ts_1.Token.HIDDEN_CHANNEL && t.type !== antlr4ts_1.Token.EOF) {
|
|
130
|
+
(0, leaf_1.emitVisibleToken)(f, t, i);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
result: f.o.toString(),
|
|
136
|
+
errors: [...lexerErrors.errors, ...parserErrors.errors],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=index.js.map
|