@prisma-next/psl-parser 0.14.0-dev.9 → 0.14.0-dev.90
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/{declarations-D9h_ihD3.mjs → declarations-DR6To8_k.mjs} +295 -55
- package/dist/declarations-DR6To8_k.mjs.map +1 -0
- package/dist/format.d.mts +1 -1
- package/dist/format.mjs +2 -2
- package/dist/index.d.mts +115 -107
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +437 -60
- package/dist/index.mjs.map +1 -1
- package/dist/interpret.d.mts +39 -0
- package/dist/interpret.d.mts.map +1 -0
- package/dist/interpret.mjs +25 -0
- package/dist/interpret.mjs.map +1 -0
- package/dist/{parse-BjZ1LPe6.d.mts → parse-BazJr7Ye.d.mts} +128 -51
- package/dist/parse-BazJr7Ye.d.mts.map +1 -0
- package/dist/{parse-DhEV6av6.mjs → parse-CdeXr0T3.mjs} +28 -7
- package/dist/parse-CdeXr0T3.mjs.map +1 -0
- package/dist/symbol-table-C-AH04Ug.d.mts +127 -0
- package/dist/symbol-table-C-AH04Ug.d.mts.map +1 -0
- package/dist/syntax.d.mts +20 -2
- package/dist/syntax.d.mts.map +1 -1
- package/dist/syntax.mjs +43 -3
- package/dist/syntax.mjs.map +1 -0
- package/package.json +10 -7
- package/src/attribute-spec/combinators/bool.ts +19 -0
- package/src/attribute-spec/combinators/diagnostic.ts +15 -0
- package/src/attribute-spec/combinators/entity-ref.ts +24 -0
- package/src/attribute-spec/combinators/field-ref.ts +36 -0
- package/src/attribute-spec/combinators/func-call.ts +65 -0
- package/src/attribute-spec/combinators/identifier.ts +16 -0
- package/src/attribute-spec/combinators/int.ts +35 -0
- package/src/attribute-spec/combinators/list.ts +43 -0
- package/src/attribute-spec/combinators/num.ts +26 -0
- package/src/attribute-spec/combinators/one-of.ts +29 -0
- package/src/attribute-spec/combinators/record.ts +43 -0
- package/src/attribute-spec/combinators/str.ts +19 -0
- package/src/attribute-spec/field-attribute.ts +27 -0
- package/src/attribute-spec/interpret.ts +177 -0
- package/src/attribute-spec/model-attribute.ts +27 -0
- package/src/attribute-spec/optional.ts +8 -0
- package/src/attribute-spec/types.ts +72 -0
- package/src/block-reconstruction.ts +1 -0
- package/src/exports/index.ts +34 -0
- package/src/exports/interpret.ts +2 -0
- package/src/exports/syntax.ts +25 -5
- package/src/interpret.ts +67 -0
- package/src/parse.ts +23 -5
- package/src/resolve.ts +4 -1
- package/src/source-file.ts +25 -0
- package/src/syntax/ast/attributes.ts +5 -6
- package/src/syntax/ast/declarations.ts +51 -26
- package/src/syntax/ast/expressions.ts +12 -13
- package/src/syntax/ast/identifier.ts +2 -3
- package/src/syntax/ast/qualified-name.ts +28 -19
- package/src/syntax/ast/type-annotation.ts +4 -5
- package/src/syntax/ast-helpers.ts +27 -3
- package/src/syntax/navigation.ts +55 -0
- package/src/syntax/red.ts +317 -42
- package/dist/declarations-D9h_ihD3.mjs.map +0 -1
- package/dist/parse-BjZ1LPe6.d.mts.map +0 -1
- package/dist/parse-DhEV6av6.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as FunctionCallAst, b as ObjectLiteralExprAst, c as NamespaceDeclarationAst, g as BooleanLiteralExprAst, i as GenericBlockDeclarationAst, k as printSyntax, l as TypesBlockAst, m as ArrayLiteralAst, o as ModelDeclarationAst, t as CompositeTypeDeclarationAst, v as NumberLiteralExprAst, w as IdentifierAst, x as StringLiteralExprAst } from "./declarations-DR6To8_k.mjs";
|
|
2
2
|
import { UNSPECIFIED_PSL_NAMESPACE_ID, flatPslModels, makePslNamespace, makePslNamespaceEntries, namespacePslExtensionBlocks, validateExtensionBlock } from "@prisma-next/framework-components/psl-ast";
|
|
3
|
+
import { notOk, ok } from "@prisma-next/utils/result";
|
|
4
|
+
import { blindCast } from "@prisma-next/utils/casts";
|
|
3
5
|
import { isAuthoringPslBlockDescriptor } from "@prisma-next/framework-components/authoring";
|
|
4
6
|
//#region src/attribute-helpers.ts
|
|
5
7
|
function getPositionalArgument(attribute, index = 0) {
|
|
@@ -11,63 +13,6 @@ function parseQuotedStringLiteral(value) {
|
|
|
11
13
|
return match[2] ?? "";
|
|
12
14
|
}
|
|
13
15
|
//#endregion
|
|
14
|
-
//#region src/extension-block.ts
|
|
15
|
-
function findBlockDescriptor(descriptors, keyword) {
|
|
16
|
-
if (descriptors === void 0) return void 0;
|
|
17
|
-
for (const value of Object.values(descriptors)) {
|
|
18
|
-
if (value === void 0) continue;
|
|
19
|
-
if (isAuthoringPslBlockDescriptor(value)) {
|
|
20
|
-
if (value.keyword === keyword) return value;
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
const nested = findBlockDescriptor(value, keyword);
|
|
24
|
-
if (nested !== void 0) return nested;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function validateExtensionBlockFromSymbol(input) {
|
|
28
|
-
const refCtx = buildRefResolutionContext(input.symbolTable, input.block);
|
|
29
|
-
return validateExtensionBlock(input.block.block, input.descriptor, input.sourceId, input.codecLookup, refCtx);
|
|
30
|
-
}
|
|
31
|
-
const ZERO_SPAN = {
|
|
32
|
-
start: {
|
|
33
|
-
offset: 0,
|
|
34
|
-
line: 1,
|
|
35
|
-
column: 1
|
|
36
|
-
},
|
|
37
|
-
end: {
|
|
38
|
-
offset: 0,
|
|
39
|
-
line: 1,
|
|
40
|
-
column: 1
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
function buildRefResolutionContext(symbolTable, block) {
|
|
44
|
-
const unspecifiedNamespace = makeNamespace(UNSPECIFIED_PSL_NAMESPACE_ID, Object.values(symbolTable.topLevel.models));
|
|
45
|
-
const allNamespaces = [unspecifiedNamespace, ...Object.values(symbolTable.topLevel.namespaces).map((namespace) => makeNamespace(namespace.name, Object.values(namespace.models)))];
|
|
46
|
-
const ownerNamespaceName = findOwnerNamespaceName(symbolTable, block);
|
|
47
|
-
return {
|
|
48
|
-
ownerNamespace: allNamespaces.find((namespace) => namespace.name === ownerNamespaceName) ?? unspecifiedNamespace,
|
|
49
|
-
allNamespaces
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function makeNamespace(name, models) {
|
|
53
|
-
return makePslNamespace({
|
|
54
|
-
kind: "namespace",
|
|
55
|
-
name,
|
|
56
|
-
entries: makePslNamespaceEntries(models.map((model) => ({
|
|
57
|
-
kind: "model",
|
|
58
|
-
name: model.name,
|
|
59
|
-
fields: [],
|
|
60
|
-
attributes: [],
|
|
61
|
-
span: ZERO_SPAN
|
|
62
|
-
})), [], []),
|
|
63
|
-
span: ZERO_SPAN
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
function findOwnerNamespaceName(symbolTable, block) {
|
|
67
|
-
for (const namespace of Object.values(symbolTable.topLevel.namespaces)) if (Object.values(namespace.blocks).some((candidate) => candidate === block)) return namespace.name;
|
|
68
|
-
return UNSPECIFIED_PSL_NAMESPACE_ID;
|
|
69
|
-
}
|
|
70
|
-
//#endregion
|
|
71
16
|
//#region src/resolve.ts
|
|
72
17
|
function readResolvedAttribute(attribute, sourceFile) {
|
|
73
18
|
return {
|
|
@@ -93,10 +38,12 @@ function readResolvedArgList(argList, sourceFile) {
|
|
|
93
38
|
const args = [];
|
|
94
39
|
for (const arg of argList.args()) {
|
|
95
40
|
const name = arg.name()?.name();
|
|
41
|
+
const expression = arg.value();
|
|
96
42
|
args.push({
|
|
97
43
|
kind: name !== void 0 ? "named" : "positional",
|
|
98
44
|
...name !== void 0 ? { name } : {},
|
|
99
|
-
value: renderExpression(
|
|
45
|
+
value: renderExpression(expression),
|
|
46
|
+
...expression !== void 0 ? { expression } : {},
|
|
100
47
|
span: nodePslSpan(arg.syntax, sourceFile)
|
|
101
48
|
});
|
|
102
49
|
}
|
|
@@ -141,6 +88,435 @@ function offsetToPslPosition(offset, sourceFile) {
|
|
|
141
88
|
};
|
|
142
89
|
}
|
|
143
90
|
//#endregion
|
|
91
|
+
//#region src/attribute-spec/combinators/diagnostic.ts
|
|
92
|
+
const ATTRIBUTE_DIAGNOSTIC_CODE = "PSL_INVALID_ATTRIBUTE_SYNTAX";
|
|
93
|
+
function leafDiagnostic(ctx, node, message) {
|
|
94
|
+
return {
|
|
95
|
+
code: ATTRIBUTE_DIAGNOSTIC_CODE,
|
|
96
|
+
message,
|
|
97
|
+
sourceId: ctx.sourceId,
|
|
98
|
+
span: nodePslSpan(node.syntax, ctx.sourceFile)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/attribute-spec/combinators/bool.ts
|
|
103
|
+
function bool() {
|
|
104
|
+
return {
|
|
105
|
+
kind: "bool",
|
|
106
|
+
label: "boolean",
|
|
107
|
+
parse: (arg, ctx) => {
|
|
108
|
+
if (arg instanceof BooleanLiteralExprAst) {
|
|
109
|
+
const value = arg.value();
|
|
110
|
+
if (value !== void 0) return ok(value);
|
|
111
|
+
}
|
|
112
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected a boolean literal")]);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/attribute-spec/combinators/entity-ref.ts
|
|
118
|
+
function entityRef() {
|
|
119
|
+
return {
|
|
120
|
+
kind: "entityRef",
|
|
121
|
+
label: "model name",
|
|
122
|
+
parse: (arg, ctx) => {
|
|
123
|
+
if (!(arg instanceof IdentifierAst)) return notOk([leafDiagnostic(ctx, arg, "Expected a model name")]);
|
|
124
|
+
const name = arg.name();
|
|
125
|
+
if (name === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a model name")]);
|
|
126
|
+
return ok(name);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/attribute-spec/combinators/field-ref.ts
|
|
132
|
+
function fieldRef(scope) {
|
|
133
|
+
return {
|
|
134
|
+
kind: "fieldRef",
|
|
135
|
+
label: "field name",
|
|
136
|
+
scope,
|
|
137
|
+
parse: (arg, ctx) => {
|
|
138
|
+
if (!(arg instanceof IdentifierAst)) return notOk([leafDiagnostic(ctx, arg, "Expected a field name")]);
|
|
139
|
+
const name = arg.name();
|
|
140
|
+
if (name === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a field name")]);
|
|
141
|
+
const model = scope === "self" ? ctx.selfModel : ctx.resolveReferencedModel();
|
|
142
|
+
if (model !== void 0 && !Object.hasOwn(model.fields, name)) return notOk([leafDiagnostic(ctx, arg, `Field "${name}" does not exist on model "${model.name}"`)]);
|
|
143
|
+
return ok(name);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region src/attribute-spec/interpret.ts
|
|
149
|
+
function interpretArgs(args, spec, ctx, span) {
|
|
150
|
+
const diagnostics = [];
|
|
151
|
+
const output = {};
|
|
152
|
+
const seen = /* @__PURE__ */ new Set();
|
|
153
|
+
let positionalSlot = 0;
|
|
154
|
+
let reportedExcess = false;
|
|
155
|
+
for (const arg of args) {
|
|
156
|
+
const name = arg.name()?.name();
|
|
157
|
+
let key;
|
|
158
|
+
let param;
|
|
159
|
+
if (name === void 0) {
|
|
160
|
+
const posParam = spec.positional[positionalSlot];
|
|
161
|
+
if (posParam === void 0) {
|
|
162
|
+
if (!reportedExcess) {
|
|
163
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" received too many positional arguments`, ctx, span));
|
|
164
|
+
reportedExcess = true;
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
positionalSlot += 1;
|
|
169
|
+
key = posParam.key;
|
|
170
|
+
param = posParam.type;
|
|
171
|
+
} else {
|
|
172
|
+
const namedParam = Object.hasOwn(spec.named, name) ? spec.named[name] : void 0;
|
|
173
|
+
if (namedParam === void 0) {
|
|
174
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" received unknown argument "${name}"`, ctx, nodePslSpan(arg.syntax, ctx.sourceFile)));
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
key = name;
|
|
178
|
+
param = namedParam;
|
|
179
|
+
}
|
|
180
|
+
if (seen.has(key)) {
|
|
181
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" received duplicate argument "${key}"`, ctx, nodePslSpan(arg.syntax, ctx.sourceFile)));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
seen.add(key);
|
|
185
|
+
const result = parseArgValue(arg, param, ctx, diagnostics);
|
|
186
|
+
if (result.ok) output[key] = result.value;
|
|
187
|
+
}
|
|
188
|
+
const finalized = /* @__PURE__ */ new Set();
|
|
189
|
+
const finalizeAbsentKey = (key, positionalParam, namedParam) => {
|
|
190
|
+
if (finalized.has(key) || seen.has(key)) return;
|
|
191
|
+
finalized.add(key);
|
|
192
|
+
const effective = namedParam ?? positionalParam;
|
|
193
|
+
if (effective === void 0) return;
|
|
194
|
+
if (isOptionalArgType(effective)) {
|
|
195
|
+
if (effective.hasDefault) output[key] = effective.defaultValue;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" is missing required argument "${key}"`, ctx, span));
|
|
199
|
+
};
|
|
200
|
+
for (const param of spec.positional) {
|
|
201
|
+
const namedParam = Object.hasOwn(spec.named, param.key) ? spec.named[param.key] : void 0;
|
|
202
|
+
finalizeAbsentKey(param.key, param.type, namedParam);
|
|
203
|
+
}
|
|
204
|
+
for (const key of Object.keys(spec.named)) finalizeAbsentKey(key, void 0, spec.named[key]);
|
|
205
|
+
if (diagnostics.length > 0) return notOk(diagnostics);
|
|
206
|
+
return ok(output);
|
|
207
|
+
}
|
|
208
|
+
function interpretAttribute(attrNode, spec, ctx) {
|
|
209
|
+
const attributeSpan = nodePslSpan(attrNode.syntax, ctx.sourceFile);
|
|
210
|
+
const bound = interpretArgs(attrNode.argList()?.args() ?? [], spec, ctx, attributeSpan);
|
|
211
|
+
if (!bound.ok) return notOk(bound.failure);
|
|
212
|
+
const value = blindCast(bound.value);
|
|
213
|
+
if (spec.refine !== void 0) {
|
|
214
|
+
const refineDiagnostics = spec.refine(value, ctx);
|
|
215
|
+
if (refineDiagnostics.length > 0) return notOk(refineDiagnostics);
|
|
216
|
+
}
|
|
217
|
+
return ok(value);
|
|
218
|
+
}
|
|
219
|
+
function parseArgValue(arg, argType, ctx, diagnostics) {
|
|
220
|
+
const value = arg.value();
|
|
221
|
+
if (value === void 0) {
|
|
222
|
+
const missing = diagnostic("Attribute argument is missing a value", ctx, nodePslSpan(arg.syntax, ctx.sourceFile));
|
|
223
|
+
diagnostics.push(missing);
|
|
224
|
+
return notOk([missing]);
|
|
225
|
+
}
|
|
226
|
+
const result = argType.parse(value, ctx);
|
|
227
|
+
if (!result.ok) for (const failure of result.failure) diagnostics.push(failure);
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
function isOptionalArgType(param) {
|
|
231
|
+
return "optional" in param && param.optional === true;
|
|
232
|
+
}
|
|
233
|
+
function diagnostic(message, ctx, span) {
|
|
234
|
+
return {
|
|
235
|
+
code: ATTRIBUTE_DIAGNOSTIC_CODE,
|
|
236
|
+
message,
|
|
237
|
+
sourceId: ctx.sourceId,
|
|
238
|
+
span
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/attribute-spec/combinators/func-call.ts
|
|
243
|
+
function funcCall(name, sig) {
|
|
244
|
+
return {
|
|
245
|
+
kind: "funcCall",
|
|
246
|
+
label: "function call",
|
|
247
|
+
parse: (arg, ctx) => {
|
|
248
|
+
const guard = matchCallee(arg, name, ctx);
|
|
249
|
+
if (!guard.ok) return guard;
|
|
250
|
+
const span = nodePslSpan(guard.value.syntax, ctx.sourceFile);
|
|
251
|
+
const bound = interpretArgs(guard.value.args(), {
|
|
252
|
+
name,
|
|
253
|
+
positional: sig.positional ?? [],
|
|
254
|
+
named: sig.named ?? {}
|
|
255
|
+
}, ctx, span);
|
|
256
|
+
if (!bound.ok) return notOk(bound.failure);
|
|
257
|
+
return ok({
|
|
258
|
+
fn: name,
|
|
259
|
+
span,
|
|
260
|
+
args: bound.value
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function matchCallee(arg, name, ctx) {
|
|
266
|
+
if (!(arg instanceof FunctionCallAst)) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
|
|
267
|
+
const qname = arg.name();
|
|
268
|
+
if (qname === void 0 || qname.dot() !== void 0 || qname.colon() !== void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
|
|
269
|
+
const calleeName = qname.identifier()?.token()?.text;
|
|
270
|
+
if (calleeName === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
|
|
271
|
+
if (calleeName !== name) return notOk([leafDiagnostic(ctx, arg, `Expected ${name}()`)]);
|
|
272
|
+
return ok(arg);
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/attribute-spec/combinators/identifier.ts
|
|
276
|
+
function identifier(name) {
|
|
277
|
+
return {
|
|
278
|
+
kind: "identifier",
|
|
279
|
+
label: name,
|
|
280
|
+
parse: (arg, ctx) => {
|
|
281
|
+
if (arg instanceof IdentifierAst && arg.name() === name) return ok(name);
|
|
282
|
+
return notOk([leafDiagnostic(ctx, arg, `Expected ${name}`)]);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/attribute-spec/combinators/int.ts
|
|
288
|
+
function int(opts) {
|
|
289
|
+
const min = opts?.min;
|
|
290
|
+
const max = opts?.max;
|
|
291
|
+
return {
|
|
292
|
+
kind: "int",
|
|
293
|
+
label: "integer",
|
|
294
|
+
parse: (arg, ctx) => {
|
|
295
|
+
if (arg instanceof NumberLiteralExprAst) {
|
|
296
|
+
const value = arg.value();
|
|
297
|
+
if (value !== void 0 && Number.isInteger(value)) {
|
|
298
|
+
if ((min === void 0 || value >= min) && (max === void 0 || value <= max)) return ok(value);
|
|
299
|
+
return notOk([leafDiagnostic(ctx, arg, rangeMessage(min, max))]);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected an integer literal")]);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function rangeMessage(min, max) {
|
|
307
|
+
if (min !== void 0 && max !== void 0) return `Expected an integer between ${min} and ${max}`;
|
|
308
|
+
if (min !== void 0) return `Expected an integer greater than or equal to ${min}`;
|
|
309
|
+
return `Expected an integer less than or equal to ${max}`;
|
|
310
|
+
}
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/attribute-spec/combinators/list.ts
|
|
313
|
+
function list(of, opts) {
|
|
314
|
+
return {
|
|
315
|
+
kind: "list",
|
|
316
|
+
label: `${of.label}[]`,
|
|
317
|
+
parse: (arg, ctx) => {
|
|
318
|
+
if (!(arg instanceof ArrayLiteralAst)) return notOk([leafDiagnostic(ctx, arg, `Expected a list of ${of.label}`)]);
|
|
319
|
+
const diagnostics = [];
|
|
320
|
+
const parsed = [];
|
|
321
|
+
let count = 0;
|
|
322
|
+
for (const element of arg.elements()) {
|
|
323
|
+
count += 1;
|
|
324
|
+
const result = of.parse(element, ctx);
|
|
325
|
+
if (result.ok) parsed.push({
|
|
326
|
+
node: element,
|
|
327
|
+
value: result.value
|
|
328
|
+
});
|
|
329
|
+
else diagnostics.push(...result.failure);
|
|
330
|
+
}
|
|
331
|
+
if (opts?.nonEmpty === true && count === 0) diagnostics.push(leafDiagnostic(ctx, arg, "Expected a non-empty list"));
|
|
332
|
+
if (opts?.unique === true) {
|
|
333
|
+
const seen = /* @__PURE__ */ new Set();
|
|
334
|
+
for (const { node, value } of parsed) if (seen.has(value)) diagnostics.push(leafDiagnostic(ctx, node, "Duplicate list entry"));
|
|
335
|
+
else seen.add(value);
|
|
336
|
+
}
|
|
337
|
+
if (diagnostics.length > 0) return notOk(diagnostics);
|
|
338
|
+
return ok(parsed.map((entry) => entry.value));
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/attribute-spec/combinators/num.ts
|
|
344
|
+
function num(value) {
|
|
345
|
+
return {
|
|
346
|
+
kind: "num",
|
|
347
|
+
label: value === void 0 ? "number" : String(value),
|
|
348
|
+
parse: (arg, ctx) => {
|
|
349
|
+
if (arg instanceof NumberLiteralExprAst) {
|
|
350
|
+
const parsed = arg.value();
|
|
351
|
+
if (parsed !== void 0 && (value === void 0 || parsed === value)) return ok(parsed);
|
|
352
|
+
}
|
|
353
|
+
return notOk([leafDiagnostic(ctx, arg, value === void 0 ? "Expected a number literal" : `Expected ${value}`)]);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/attribute-spec/combinators/one-of.ts
|
|
359
|
+
function oneOf(...alts) {
|
|
360
|
+
const label = alts.map((alt) => alt.label).join(" | ");
|
|
361
|
+
return {
|
|
362
|
+
kind: "oneOf",
|
|
363
|
+
label,
|
|
364
|
+
parse: (arg, ctx) => {
|
|
365
|
+
for (const alt of alts) {
|
|
366
|
+
const result = alt.parse(arg, ctx);
|
|
367
|
+
if (result.ok) return ok(blindCast(result.value));
|
|
368
|
+
}
|
|
369
|
+
return notOk([leafDiagnostic(ctx, arg, `Expected one of: ${label}`)]);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/attribute-spec/combinators/record.ts
|
|
375
|
+
function record(of) {
|
|
376
|
+
return {
|
|
377
|
+
kind: "record",
|
|
378
|
+
label: `{ [key]: ${of.label} }`,
|
|
379
|
+
parse: (arg, ctx) => {
|
|
380
|
+
if (!(arg instanceof ObjectLiteralExprAst)) return notOk([leafDiagnostic(ctx, arg, "Expected an object literal")]);
|
|
381
|
+
const diagnostics = [];
|
|
382
|
+
const result = {};
|
|
383
|
+
for (const field of arg.fields()) {
|
|
384
|
+
const key = field.keyName();
|
|
385
|
+
if (key === void 0) {
|
|
386
|
+
diagnostics.push(leafDiagnostic(ctx, field, "Expected a key"));
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const value = field.value();
|
|
390
|
+
if (value === void 0) {
|
|
391
|
+
diagnostics.push(leafDiagnostic(ctx, field, `Expected a value for key "${key}"`));
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const parsed = of.parse(value, ctx);
|
|
395
|
+
if (!parsed.ok) {
|
|
396
|
+
diagnostics.push(...parsed.failure);
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (Object.hasOwn(result, key)) {
|
|
400
|
+
diagnostics.push(leafDiagnostic(ctx, field, `Duplicate key "${key}"`));
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
result[key] = parsed.value;
|
|
404
|
+
}
|
|
405
|
+
if (diagnostics.length > 0) return notOk(diagnostics);
|
|
406
|
+
return ok(result);
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
//#endregion
|
|
411
|
+
//#region src/attribute-spec/combinators/str.ts
|
|
412
|
+
function str() {
|
|
413
|
+
return {
|
|
414
|
+
kind: "str",
|
|
415
|
+
label: "string",
|
|
416
|
+
parse: (arg, ctx) => {
|
|
417
|
+
if (arg instanceof StringLiteralExprAst) {
|
|
418
|
+
const value = arg.value();
|
|
419
|
+
if (value !== void 0) return ok(value);
|
|
420
|
+
}
|
|
421
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected a string literal")]);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/attribute-spec/field-attribute.ts
|
|
427
|
+
function fieldAttribute(name, config) {
|
|
428
|
+
return {
|
|
429
|
+
level: "field",
|
|
430
|
+
name,
|
|
431
|
+
positional: config.positional ?? [],
|
|
432
|
+
named: config.named ?? {},
|
|
433
|
+
...config.refine !== void 0 ? { refine: config.refine } : {}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/attribute-spec/model-attribute.ts
|
|
438
|
+
function modelAttribute(name, config) {
|
|
439
|
+
return {
|
|
440
|
+
level: "model",
|
|
441
|
+
name,
|
|
442
|
+
positional: config.positional ?? [],
|
|
443
|
+
named: config.named ?? {},
|
|
444
|
+
...config.refine !== void 0 ? { refine: config.refine } : {}
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
//#endregion
|
|
448
|
+
//#region src/attribute-spec/optional.ts
|
|
449
|
+
function optional(type, ...rest) {
|
|
450
|
+
if (rest.length === 0) return {
|
|
451
|
+
...type,
|
|
452
|
+
optional: true,
|
|
453
|
+
hasDefault: false
|
|
454
|
+
};
|
|
455
|
+
return {
|
|
456
|
+
...type,
|
|
457
|
+
optional: true,
|
|
458
|
+
hasDefault: true,
|
|
459
|
+
defaultValue: rest[0]
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
//#endregion
|
|
463
|
+
//#region src/extension-block.ts
|
|
464
|
+
function findBlockDescriptor(descriptors, keyword) {
|
|
465
|
+
if (descriptors === void 0) return void 0;
|
|
466
|
+
for (const value of Object.values(descriptors)) {
|
|
467
|
+
if (value === void 0) continue;
|
|
468
|
+
if (isAuthoringPslBlockDescriptor(value)) {
|
|
469
|
+
if (value.keyword === keyword) return value;
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
const nested = findBlockDescriptor(value, keyword);
|
|
473
|
+
if (nested !== void 0) return nested;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function validateExtensionBlockFromSymbol(input) {
|
|
477
|
+
const refCtx = buildRefResolutionContext(input.symbolTable, input.block);
|
|
478
|
+
return validateExtensionBlock(input.block.block, input.descriptor, input.sourceId, input.codecLookup, refCtx);
|
|
479
|
+
}
|
|
480
|
+
const ZERO_SPAN = {
|
|
481
|
+
start: {
|
|
482
|
+
offset: 0,
|
|
483
|
+
line: 1,
|
|
484
|
+
column: 1
|
|
485
|
+
},
|
|
486
|
+
end: {
|
|
487
|
+
offset: 0,
|
|
488
|
+
line: 1,
|
|
489
|
+
column: 1
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
function buildRefResolutionContext(symbolTable, block) {
|
|
493
|
+
const unspecifiedNamespace = makeNamespace(UNSPECIFIED_PSL_NAMESPACE_ID, Object.values(symbolTable.topLevel.models));
|
|
494
|
+
const allNamespaces = [unspecifiedNamespace, ...Object.values(symbolTable.topLevel.namespaces).map((namespace) => makeNamespace(namespace.name, Object.values(namespace.models)))];
|
|
495
|
+
const ownerNamespaceName = findOwnerNamespaceName(symbolTable, block);
|
|
496
|
+
return {
|
|
497
|
+
ownerNamespace: allNamespaces.find((namespace) => namespace.name === ownerNamespaceName) ?? unspecifiedNamespace,
|
|
498
|
+
allNamespaces
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function makeNamespace(name, models) {
|
|
502
|
+
return makePslNamespace({
|
|
503
|
+
kind: "namespace",
|
|
504
|
+
name,
|
|
505
|
+
entries: makePslNamespaceEntries(models.map((model) => ({
|
|
506
|
+
kind: "model",
|
|
507
|
+
name: model.name,
|
|
508
|
+
fields: [],
|
|
509
|
+
attributes: [],
|
|
510
|
+
span: ZERO_SPAN
|
|
511
|
+
})), [], []),
|
|
512
|
+
span: ZERO_SPAN
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function findOwnerNamespaceName(symbolTable, block) {
|
|
516
|
+
for (const namespace of Object.values(symbolTable.topLevel.namespaces)) if (Object.values(namespace.blocks).some((candidate) => candidate === block)) return namespace.name;
|
|
517
|
+
return UNSPECIFIED_PSL_NAMESPACE_ID;
|
|
518
|
+
}
|
|
519
|
+
//#endregion
|
|
144
520
|
//#region src/block-reconstruction.ts
|
|
145
521
|
/**
|
|
146
522
|
* Descriptor-free and unknown parameters become `value` stubs so validation can
|
|
@@ -186,6 +562,7 @@ function reconstructExtensionBlock(node, descriptor, sourceFile, diagnostics) {
|
|
|
186
562
|
}
|
|
187
563
|
return {
|
|
188
564
|
kind: descriptor?.discriminator ?? keyword,
|
|
565
|
+
keyword,
|
|
189
566
|
name: blockName,
|
|
190
567
|
parameters,
|
|
191
568
|
blockAttributes,
|
|
@@ -479,6 +856,6 @@ function nodeRange(node, sourceFile) {
|
|
|
479
856
|
};
|
|
480
857
|
}
|
|
481
858
|
//#endregion
|
|
482
|
-
export { buildSymbolTable, findBlockDescriptor, flatPslModels, getPositionalArgument, keywordPslSpan, namespacePslExtensionBlocks, nodePslSpan, parseQuotedStringLiteral, rangeToPslSpan, readResolvedAttribute, readResolvedAttributes, readResolvedConstructorCall, validateExtensionBlockFromSymbol };
|
|
859
|
+
export { bool, buildSymbolTable, entityRef, fieldAttribute, fieldRef, findBlockDescriptor, flatPslModels, funcCall, getPositionalArgument, identifier, int, interpretArgs, interpretAttribute, keywordPslSpan, leafDiagnostic, list, modelAttribute, namespacePslExtensionBlocks, nodePslSpan, num, oneOf, optional, parseQuotedStringLiteral, rangeToPslSpan, readResolvedAttribute, readResolvedAttributes, readResolvedConstructorCall, record, str, validateExtensionBlockFromSymbol };
|
|
483
860
|
|
|
484
861
|
//# sourceMappingURL=index.mjs.map
|