@jigs.design/compiler 0.0.0-stage → 0.1.0
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 +21 -0
- package/README.md +28 -2
- package/dist/ast.d.ts +78 -0
- package/dist/block-hoist.js +237 -0
- package/dist/check-code.d.ts +46 -0
- package/dist/check-code.js +700 -0
- package/dist/codegen.d.ts +8 -0
- package/dist/codegen.js +219 -0
- package/dist/compile.d.ts +177 -0
- package/dist/compile.js +950 -0
- package/dist/hoist.d.ts +20 -0
- package/dist/hoist.js +76 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +9 -0
- package/dist/offsets.d.ts +18 -0
- package/dist/offsets.js +40 -0
- package/dist/parse.d.ts +16 -0
- package/dist/parse.js +690 -0
- package/dist/patch.d.ts +55 -0
- package/dist/patch.js +140 -0
- package/dist/script.d.ts +14 -0
- package/dist/script.js +695 -0
- package/dist/signature.d.ts +5 -0
- package/dist/signature.js +25 -0
- package/dist/spec.d.ts +29 -0
- package/dist/spec.js +14 -0
- package/dist/suggest.d.ts +8 -0
- package/dist/suggest.js +53 -0
- package/package.json +27 -3
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/codegen.d.ts
|
|
2
|
+
/** What the sandbox runs: a JavaScript program plus the text it displays. */
|
|
3
|
+
export interface ProgramOutput {
|
|
4
|
+
code: string;
|
|
5
|
+
/** Static text, kept out of `code` so growing text doesn't change the program. */
|
|
6
|
+
constants: Readonly<Record<string, string>>;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
package/dist/codegen.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { analyze, isValidBinding } from "./script.js";
|
|
2
|
+
//#region src/codegen.ts
|
|
3
|
+
/**
|
|
4
|
+
* Adds `{ key }` to single-argument `useState(...)` and `useMutation(...)`
|
|
5
|
+
* calls, bare or with `Pickle.`, named after the declaration, so state and a
|
|
6
|
+
* mutation's status survive recompiles and reordering. The calls come from the
|
|
7
|
+
* parser, so text that only looks like one, in a string or a comment, is left
|
|
8
|
+
* alone.
|
|
9
|
+
*/
|
|
10
|
+
function injectStateKeys(code, baseKey) {
|
|
11
|
+
const analysis = analyze(code, "statement");
|
|
12
|
+
if (!analysis.ok) return code;
|
|
13
|
+
const counts = /* @__PURE__ */ new Map();
|
|
14
|
+
const inserts = [];
|
|
15
|
+
for (const call of analysis.keyed.toSorted((a, b) => a.start - b.start)) {
|
|
16
|
+
const calls = counts.get(call.hook) ?? 0;
|
|
17
|
+
counts.set(call.hook, calls + 1);
|
|
18
|
+
if (call.arguments > 1) continue;
|
|
19
|
+
const key = JSON.stringify(calls === 0 ? baseKey : `${baseKey}#${calls}`);
|
|
20
|
+
inserts.push({
|
|
21
|
+
at: call.insertAt,
|
|
22
|
+
text: `${call.arguments === 0 ? "undefined" : ""}, { key: ${key} }`
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
let result = "";
|
|
26
|
+
let cursor = 0;
|
|
27
|
+
for (const insert of inserts.toSorted((a, b) => a.at - b.at)) {
|
|
28
|
+
result += code.slice(cursor, insert.at) + insert.text;
|
|
29
|
+
cursor = insert.at;
|
|
30
|
+
}
|
|
31
|
+
return result + code.slice(cursor);
|
|
32
|
+
}
|
|
33
|
+
/** Names a spec may not declare: the runtime's own bindings. */
|
|
34
|
+
const RESERVED = /* @__PURE__ */ new Set([
|
|
35
|
+
"Pickle",
|
|
36
|
+
"useMutation",
|
|
37
|
+
"useQuery",
|
|
38
|
+
"useState"
|
|
39
|
+
]);
|
|
40
|
+
const isReserved = (name) => RESERVED.has(name) || name.startsWith("__pickle");
|
|
41
|
+
/** Whether `name` can be bound as a loop variable without hiding the runtime's own names. */
|
|
42
|
+
function isBindingName(name) {
|
|
43
|
+
return !isReserved(name) && isValidBinding(name);
|
|
44
|
+
}
|
|
45
|
+
/** Why a `{@body}` line is removed, or null when it is kept. */
|
|
46
|
+
function statementProblem(code) {
|
|
47
|
+
const analysis = analyze(code, "statement");
|
|
48
|
+
if (!analysis.ok) return analysis.message.includes("'return' outside of function") ? "`return` can't be used in a {@body} line: the page always renders. To hide markup, wrap it in <if test={…}>. The line was removed" : `{@body} line is not valid JavaScript (${analysis.message}); it was removed`;
|
|
49
|
+
const reserved = analysis.declared.find(isReserved);
|
|
50
|
+
return reserved === void 0 ? null : `{@body} line declares "${reserved}", a name Pickle uses itself; rename it. The line was removed`;
|
|
51
|
+
}
|
|
52
|
+
/** Why `code` can't be spliced in as an expression, or null when it can. */
|
|
53
|
+
function expressionProblem(code) {
|
|
54
|
+
const analysis = analyze(code, "expression");
|
|
55
|
+
return analysis.ok ? null : analysis.message;
|
|
56
|
+
}
|
|
57
|
+
const fragment = (children) => `__pickle.jsx(${[
|
|
58
|
+
"__pickle.Fragment",
|
|
59
|
+
"null",
|
|
60
|
+
...children
|
|
61
|
+
].join(", ")})`;
|
|
62
|
+
const documentLines = { line: String };
|
|
63
|
+
const libraryLines = { line: () => "__pickleAt" };
|
|
64
|
+
function generateProgram(statements, tree, defines = []) {
|
|
65
|
+
const diagnostics = [];
|
|
66
|
+
const constants = {};
|
|
67
|
+
let nextConstant = 0;
|
|
68
|
+
const invalid = (code, line, message) => {
|
|
69
|
+
diagnostics.push({
|
|
70
|
+
code,
|
|
71
|
+
line,
|
|
72
|
+
message,
|
|
73
|
+
severity: "warning"
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
/** Statement lines, run in order, plus a `let` for every name they declare. */
|
|
77
|
+
const genStatements = (list, lines) => {
|
|
78
|
+
const declared = /* @__PURE__ */ new Set();
|
|
79
|
+
const body = [];
|
|
80
|
+
for (const statement of list) {
|
|
81
|
+
const problem = statementProblem(statement.code);
|
|
82
|
+
const analysis = analyze(statement.code, "statement");
|
|
83
|
+
if (problem !== null || !analysis.ok) {
|
|
84
|
+
invalid("invalid_statement", statement.line, problem ?? "");
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const names = analysis.declared;
|
|
88
|
+
for (const name of names) declared.add(name);
|
|
89
|
+
const code = injectStateKeys(statement.code, names[0] ?? `statement:${statement.line}`);
|
|
90
|
+
const run = names.length === 0 ? `(() => {\n${code}\n})();` : `({ ${names.join(", ")} } = (() => {\n${code}\nreturn { ${names.join(", ")} };\n})());`;
|
|
91
|
+
body.push(`try {\n${run}\n} catch (error) { Pickle.reportError(${lines.line(statement.line)}, error); }`);
|
|
92
|
+
}
|
|
93
|
+
return declared.size > 0 ? [`let ${[...declared].join(", ")};`, ...body] : body;
|
|
94
|
+
};
|
|
95
|
+
const genPropEntries = (entries, line, label) => {
|
|
96
|
+
let dynamic = false;
|
|
97
|
+
const props = [];
|
|
98
|
+
for (const [name, value] of Object.entries(entries)) {
|
|
99
|
+
if (value.kind === "literal") {
|
|
100
|
+
props.push(`${JSON.stringify(name)}: ${JSON.stringify(value.value)}`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const problem = expressionProblem(value.code);
|
|
104
|
+
if (problem === null) {
|
|
105
|
+
dynamic = true;
|
|
106
|
+
props.push(`${JSON.stringify(name)}: (${value.code}\n)`);
|
|
107
|
+
} else invalid("invalid_expression", line, `<${label} ${name}={${value.code}}> is not a valid expression (${problem}); the prop was removed`);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
dynamic,
|
|
111
|
+
props
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
const genChildren = (nodes, lines) => nodes.map((child) => genNode(child, lines)).filter((child) => child !== null);
|
|
115
|
+
const genNode = (node, lines) => {
|
|
116
|
+
switch (node.type) {
|
|
117
|
+
case "each": {
|
|
118
|
+
const problem = expressionProblem(node.items);
|
|
119
|
+
if (problem !== null) {
|
|
120
|
+
invalid("invalid_expression", node.line, `<each of={${node.items}}> is not a valid expression (${problem}); it was removed`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const params = [node.item, ...node.index === null ? [] : [node.index]];
|
|
124
|
+
const iteration = [...genStatements(node.statements, lines), `return ${fragment(genChildren(node.children, lines))};`].join("\n");
|
|
125
|
+
const at = lines.line(node.line);
|
|
126
|
+
return `__pickleSafe(() => __pickle.each((${node.items}\n), (${params.join(", ")}) => {\n${iteration}\n}, ${at}), null, ${at})`;
|
|
127
|
+
}
|
|
128
|
+
case "if": {
|
|
129
|
+
const problem = expressionProblem(node.test);
|
|
130
|
+
if (problem !== null) {
|
|
131
|
+
invalid("invalid_expression", node.line, `<if test={${node.test}}> is not a valid expression (${problem}); it was removed`);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const shown = node.statements.length === 0 ? fragment(genChildren(node.children, lines)) : `(() => {\n${[...genStatements(node.statements, lines), `return ${fragment(genChildren(node.children, lines))};`].join("\n")}\n})()`;
|
|
135
|
+
const at = lines.line(node.line);
|
|
136
|
+
return `__pickleSafe(() => (${node.test}\n) ? ${shown} : null, null, ${at})`;
|
|
137
|
+
}
|
|
138
|
+
case "text": {
|
|
139
|
+
const key = String(nextConstant++);
|
|
140
|
+
constants[key] = node.value;
|
|
141
|
+
return `__pickleConstants[${JSON.stringify(key)}]`;
|
|
142
|
+
}
|
|
143
|
+
case "expr": {
|
|
144
|
+
const problem = expressionProblem(node.code);
|
|
145
|
+
if (problem !== null) {
|
|
146
|
+
invalid("invalid_expression", node.line, `{${node.code}} is not a valid expression (${problem}); it was removed`);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return `__pickleSafe(() => (${node.code}\n), null, ${lines.line(node.line)})`;
|
|
150
|
+
}
|
|
151
|
+
case "element": {
|
|
152
|
+
const propEntries = genPropEntries(node.props, node.line, node.component);
|
|
153
|
+
const children = genChildren(node.children, lines);
|
|
154
|
+
const element = `__pickle.jsx(${[
|
|
155
|
+
JSON.stringify(node.component),
|
|
156
|
+
`{ ${propEntries.props.join(", ")} }`,
|
|
157
|
+
...children
|
|
158
|
+
].join(", ")})`;
|
|
159
|
+
return propEntries.dynamic ? `__pickleSafe(() => ${element}, null, ${lines.line(node.line)})` : element;
|
|
160
|
+
}
|
|
161
|
+
case "slot": return "__pickleChildren";
|
|
162
|
+
case "call": {
|
|
163
|
+
const at = lines.line(node.line);
|
|
164
|
+
const entries = node.key === null ? node.props : {
|
|
165
|
+
...node.props,
|
|
166
|
+
key: node.key
|
|
167
|
+
};
|
|
168
|
+
const props = genPropEntries(entries, node.line, node.name).props;
|
|
169
|
+
const childExprs = genChildren(node.children, lines);
|
|
170
|
+
const children = childExprs.length === 0 ? "null" : childExprs.length === 1 ? childExprs[0] ?? "null" : fragment(childExprs);
|
|
171
|
+
const library = node.origin === "library" ? ", true" : "";
|
|
172
|
+
return `__pickleSafe(() => __pickle.call(__pickleDef_${node.name}, { ${props.join(", ")} }, ${children}, ${at}, ${node.ordinal}, ${JSON.stringify(node.name)}${library}), null, ${at})`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const genBinding = (prop, lines, line) => {
|
|
177
|
+
const read = `__pickleProps.${prop.name}`;
|
|
178
|
+
if (prop.required || prop.defaultValue === null) return `const ${prop.name} = ${read};`;
|
|
179
|
+
if (prop.defaultValue.kind === "literal") return `const ${prop.name} = ${read} !== undefined ? ${read} : ${JSON.stringify(prop.defaultValue.value)};`;
|
|
180
|
+
const problem = expressionProblem(prop.defaultValue.code);
|
|
181
|
+
if (problem !== null) {
|
|
182
|
+
invalid("invalid_expression", line, `<define ${prop.name}={${prop.defaultValue.code}}> is not a valid expression (${problem}); the default was removed`);
|
|
183
|
+
return `const ${prop.name} = ${read};`;
|
|
184
|
+
}
|
|
185
|
+
return `const ${prop.name} = ${read} !== undefined ? ${read} : __pickleSafe(() => (${prop.defaultValue.code}\n), undefined, ${lines.line(line)});`;
|
|
186
|
+
};
|
|
187
|
+
const genDefine = (def) => {
|
|
188
|
+
const lines = def.origin === "library" ? libraryLines : documentLines;
|
|
189
|
+
const bindings = def.props.map((prop) => genBinding(prop, lines, def.line));
|
|
190
|
+
const view = fragment(genChildren(def.body, lines));
|
|
191
|
+
const bodyStatements = genStatements(def.statements, lines);
|
|
192
|
+
const body = bodyStatements.length === 0 ? `return ${view};` : `return (() => {\n${bodyStatements.join("\n")}\nreturn ${view};\n})();`;
|
|
193
|
+
return `function __pickleDef_${def.name}(__pickleProps, __pickleChildren, __pickleAt) {\n${[...bindings, body].join("\n")}\n}`;
|
|
194
|
+
};
|
|
195
|
+
const functions = defines.map((def) => genDefine(def));
|
|
196
|
+
const children = genChildren(tree, documentLines);
|
|
197
|
+
return {
|
|
198
|
+
diagnostics,
|
|
199
|
+
output: {
|
|
200
|
+
code: [
|
|
201
|
+
"\"use strict\";",
|
|
202
|
+
"const __pickleConstants = Pickle.useConstants();",
|
|
203
|
+
"const useState = Pickle.useState, useQuery = Pickle.useQuery, useMutation = Pickle.useMutation;",
|
|
204
|
+
...functions,
|
|
205
|
+
"Pickle.render(__pickle.jsx(() => {",
|
|
206
|
+
...genStatements(statements, documentLines),
|
|
207
|
+
`return __pickle.jsx(${[
|
|
208
|
+
"__pickle.Fragment",
|
|
209
|
+
"null",
|
|
210
|
+
...children
|
|
211
|
+
].join(",\n")});`,
|
|
212
|
+
"}, { key: \"body\" }));"
|
|
213
|
+
].filter((line) => line !== "").join("\n"),
|
|
214
|
+
constants
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
export { generateProgram, injectStateKeys, isBindingName, statementProblem };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { OffsetMap } from "./offsets.js";
|
|
2
|
+
import { ExprNode, PropValue, Statement, TextNode } from "./ast.js";
|
|
3
|
+
import { CompileCatalog } from "./spec.js";
|
|
4
|
+
import { ProgramOutput } from "./codegen.js";
|
|
5
|
+
import { DataRead, ProcedureUse } from "./check-code.js";
|
|
6
|
+
//#region src/compile.d.ts
|
|
7
|
+
type DiagnosticCode = "coerced" | "handle_field" | "hook_placement" | "invalid_control" | "invalid_define" | "invalid_expression" | "invalid_literal" | "invalid_statement" | "missing_declarations" | "missing_prop" | "mutate_in_render" | "outer_reference" | "query_options" | "repaired" | "shadows_library" | "unclosed" | "undefined_compare" | "undefined_reference" | "unexpected_children" | "unknown_component" | "unknown_prop" | "unstable_input" | "unsupported_syntax" | "use_before_declare";
|
|
8
|
+
/** Replace `[start, end)` of the source with `text`. */
|
|
9
|
+
interface FixEdit {
|
|
10
|
+
end: number;
|
|
11
|
+
start: number;
|
|
12
|
+
text: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A rewrite that makes a diagnostic's problem go away. The compiler attaches
|
|
16
|
+
* one only when there is a single way to write it, and applies it itself:
|
|
17
|
+
* see `compilePickle`.
|
|
18
|
+
*/
|
|
19
|
+
export interface Fix {
|
|
20
|
+
edits: Array<FixEdit>;
|
|
21
|
+
/** What the fix does, such as "Replace with `q.status === "pending"`". */
|
|
22
|
+
title: string;
|
|
23
|
+
}
|
|
24
|
+
export interface Diagnostic {
|
|
25
|
+
code: DiagnosticCode;
|
|
26
|
+
/** The 1-based column of `start` on its line. */
|
|
27
|
+
column?: number;
|
|
28
|
+
/** Just past what the diagnostic is about, as an offset into the source. */
|
|
29
|
+
end?: number;
|
|
30
|
+
fix?: Fix;
|
|
31
|
+
/** The line of `start` when there is one. */
|
|
32
|
+
line: number;
|
|
33
|
+
message: string;
|
|
34
|
+
severity: "info" | "warning";
|
|
35
|
+
/** The first character of what the diagnostic is about, as an offset into the source. */
|
|
36
|
+
start?: number;
|
|
37
|
+
}
|
|
38
|
+
interface RenderElement {
|
|
39
|
+
children: Array<RenderNode>;
|
|
40
|
+
component: string;
|
|
41
|
+
line: number;
|
|
42
|
+
props: Record<string, PropValue>;
|
|
43
|
+
type: "element";
|
|
44
|
+
}
|
|
45
|
+
/** `<each of={items} as="item" index="i">`: children repeated per item. */
|
|
46
|
+
interface RenderEach {
|
|
47
|
+
children: Array<RenderNode>;
|
|
48
|
+
index: string | null;
|
|
49
|
+
item: string;
|
|
50
|
+
/** JavaScript expression for the list (or a count). */
|
|
51
|
+
items: string;
|
|
52
|
+
/** Places `items` in the source; a literal list has no place. */
|
|
53
|
+
itemsAt: OffsetMap | undefined;
|
|
54
|
+
line: number;
|
|
55
|
+
/** `{@body}` lines inside the block, run at the start of every iteration. */
|
|
56
|
+
statements: Array<Statement>;
|
|
57
|
+
type: "each";
|
|
58
|
+
}
|
|
59
|
+
/** `<if test={condition}>`: children shown only when the condition is truthy. */
|
|
60
|
+
interface RenderIf {
|
|
61
|
+
children: Array<RenderNode>;
|
|
62
|
+
line: number;
|
|
63
|
+
/** `{@body}` lines inside the block, run only when the test passes. */
|
|
64
|
+
statements: Array<Statement>;
|
|
65
|
+
test: string;
|
|
66
|
+
/** Places `test` in the source; a literal test has no place. */
|
|
67
|
+
testAt: OffsetMap | undefined;
|
|
68
|
+
type: "if";
|
|
69
|
+
}
|
|
70
|
+
/** `<statCard ...>`: one call to a document-local or library component. */
|
|
71
|
+
interface RenderCall {
|
|
72
|
+
children: Array<RenderNode>;
|
|
73
|
+
/** Instance identity. Stripped before the body runs; not a define prop. */
|
|
74
|
+
key: PropValue | null;
|
|
75
|
+
line: number;
|
|
76
|
+
name: string;
|
|
77
|
+
/** 0-based source-order index of this name in the enclosing body. */
|
|
78
|
+
ordinal: number;
|
|
79
|
+
origin: "doc" | "library";
|
|
80
|
+
props: Record<string, PropValue>;
|
|
81
|
+
type: "call";
|
|
82
|
+
}
|
|
83
|
+
/** `<slot/>` inside a `<define>`: where the instance's children are inserted. */
|
|
84
|
+
interface RenderSlot {
|
|
85
|
+
line: number;
|
|
86
|
+
type: "slot";
|
|
87
|
+
}
|
|
88
|
+
export type RenderNode = ExprNode | RenderCall | RenderEach | RenderElement | RenderIf | RenderSlot | TextNode;
|
|
89
|
+
type PropKind = "boolean" | "number" | "string";
|
|
90
|
+
/** A prop on a `<define>` signature. */
|
|
91
|
+
export interface DefineProp {
|
|
92
|
+
defaultValue: PropValue | null;
|
|
93
|
+
kind: PropKind | null;
|
|
94
|
+
name: string;
|
|
95
|
+
required: boolean;
|
|
96
|
+
}
|
|
97
|
+
/** A component function the program can call. `body` sees its props and its own state. */
|
|
98
|
+
export interface CompiledDefine {
|
|
99
|
+
body: Array<RenderNode>;
|
|
100
|
+
hasSlot: boolean;
|
|
101
|
+
/** Still streaming in (the parser closed it), so its `<slot/>` may not have arrived yet. */
|
|
102
|
+
incomplete?: boolean;
|
|
103
|
+
line: number;
|
|
104
|
+
name: string;
|
|
105
|
+
origin: "doc" | "library";
|
|
106
|
+
/**
|
|
107
|
+
* The procedure calls in a library recipe's source, by its lines. Empty
|
|
108
|
+
* for a document's own define: those are on the document's result.
|
|
109
|
+
*/
|
|
110
|
+
procedures: ReadonlyArray<ProcedureUse>;
|
|
111
|
+
props: Array<DefineProp>;
|
|
112
|
+
statements: Array<Statement>;
|
|
113
|
+
}
|
|
114
|
+
/** One component the document actually renders, and how often it is written. */
|
|
115
|
+
interface DefineUse {
|
|
116
|
+
instances: number;
|
|
117
|
+
name: string;
|
|
118
|
+
origin: "doc" | "library";
|
|
119
|
+
}
|
|
120
|
+
/** Validated output: every element and literal prop is known to the catalog. */
|
|
121
|
+
export interface Program {
|
|
122
|
+
defines: Array<DefineUse>;
|
|
123
|
+
statements: Array<Statement>;
|
|
124
|
+
tree: Array<RenderNode>;
|
|
125
|
+
}
|
|
126
|
+
/** A reusable component written in Pickle: source with exactly one `<define>`. */
|
|
127
|
+
export interface Recipe {
|
|
128
|
+
name: string;
|
|
129
|
+
source: string;
|
|
130
|
+
}
|
|
131
|
+
/** Recipes compiled against one catalog, ready to use in documents. */
|
|
132
|
+
export type Library = ReadonlyMap<string, CompiledDefine>;
|
|
133
|
+
export interface CompileOptions {
|
|
134
|
+
/** The components a document may use. */
|
|
135
|
+
catalog: CompileCatalog;
|
|
136
|
+
/** Recipes in scope, from `compileLibrary` with the same catalog. */
|
|
137
|
+
library?: Library;
|
|
138
|
+
}
|
|
139
|
+
export interface CompileResult {
|
|
140
|
+
defines: ReadonlyArray<CompiledDefine>;
|
|
141
|
+
diagnostics: Array<Diagnostic>;
|
|
142
|
+
/** The recipes this document was compiled against. */
|
|
143
|
+
library: ReadonlyMap<string, CompiledDefine>;
|
|
144
|
+
output: ProgramOutput;
|
|
145
|
+
/**
|
|
146
|
+
* Every `useQuery`, `useMutation` and `useAction` call in the parsed
|
|
147
|
+
* code of the document and its defines, in line order: nothing in
|
|
148
|
+
* prose or in string literals. Recipes' calls are on the library's
|
|
149
|
+
* defines.
|
|
150
|
+
*/
|
|
151
|
+
procedures: ReadonlyArray<ProcedureUse>;
|
|
152
|
+
program: Program;
|
|
153
|
+
/** Fields the document reads from procedures' data, for the server to check. */
|
|
154
|
+
reads: ReadonlyArray<DataRead>;
|
|
155
|
+
/**
|
|
156
|
+
* The source `program` was compiled from: the one passed in, or that
|
|
157
|
+
* source with the fixes applied. It names every tag the program draws.
|
|
158
|
+
*/
|
|
159
|
+
source: string;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Compiles `recipes` against `catalog`, in order: a recipe may use the ones
|
|
163
|
+
* before it. Throws when a recipe has any diagnostic. Cached per catalog and
|
|
164
|
+
* recipe list.
|
|
165
|
+
*/
|
|
166
|
+
export declare function compileLibrary(recipes: ReadonlyArray<Recipe>, catalog: CompileCatalog): Library;
|
|
167
|
+
/**
|
|
168
|
+
* Compiles a document. A warning that carries a fix is applied rather than
|
|
169
|
+
* sent to the model: the fixed source is compiled again, and when it has
|
|
170
|
+
* exactly the problems left that the fixes did not cover, its program is
|
|
171
|
+
* used and those warnings become `info`, as a quoted number on a number prop
|
|
172
|
+
* already is. Diagnostics, procedures and their spans stay those of `source`,
|
|
173
|
+
* which is what the model wrote and what the session keeps.
|
|
174
|
+
*/
|
|
175
|
+
export declare function compilePickle(source: string, options: CompileOptions): CompileResult;
|
|
176
|
+
//#endregion
|
|
177
|
+
export {};
|