@prisma/orm-framework 8.0.0-rc.17-dev.30 → 8.0.0-rc.17-dev.31
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/{binder-BUBLuGg4-FHQS0pec.d.mts → binder-C54tCWu0-YeQvj5dt.d.mts} +28 -11
- package/dist/binder-C54tCWu0-YeQvj5dt.d.mts.map +1 -0
- package/dist/{declarations-CTFzoo9j-BaCuW9E2.mjs → declarations-DuSbyF44-Bee8mK-C.mjs} +45 -42
- package/dist/declarations-DuSbyF44-Bee8mK-C.mjs.map +1 -0
- package/dist/{parse-By_H285C-ddnkFvv5.d.mts → parse-CJtBvEYy-CbVyKoyo.d.mts} +5 -4
- package/dist/{parse-By_H285C-ddnkFvv5.d.mts.map → parse-CJtBvEYy-CbVyKoyo.d.mts.map} +1 -1
- package/dist/{parse-pRqRBDoL-BFDjYuLU.mjs → parse-DdIfS_Zs-IruUu4RY.mjs} +4 -4
- package/dist/{parse-pRqRBDoL-BFDjYuLU.mjs.map → parse-DdIfS_Zs-IruUu4RY.mjs.map} +1 -1
- package/dist/psl-parser.d.mts +4 -4
- package/dist/psl-parser.d.mts.map +1 -1
- package/dist/psl-parser.mjs +484 -298
- package/dist/psl-parser.mjs.map +1 -1
- package/dist/psl-parser__format.mjs +2 -2
- package/dist/psl-parser__format.mjs.map +1 -1
- package/dist/psl-parser__interpret.d.mts +2 -2
- package/dist/psl-parser__syntax.d.mts +1 -1
- package/dist/psl-parser__syntax.mjs +2 -2
- package/package.json +15 -15
- package/dist/binder-BUBLuGg4-FHQS0pec.d.mts.map +0 -1
- package/dist/declarations-CTFzoo9j-BaCuW9E2.mjs.map +0 -1
package/dist/psl-parser.mjs
CHANGED
|
@@ -5,10 +5,11 @@ import { r as createDataTypeLookup } from "./data-type-4xQlxYB5-DD158cOq.mjs";
|
|
|
5
5
|
import { S as isAuthoringPslBlockDescriptor, f as describeTaggedLiteralFailure, x as isAuthoringModelAttributeDescriptor } from "./temporal-presets-DEyPX8qQ-Bz4DdZ8v.mjs";
|
|
6
6
|
import { _ as readWrittenValue, a as describeExpected, d as exactRewrite, i as describeAdmittedForms, n as admittedTags, o as describeRefusal, r as castTypedValue, t as admittedForms, v as tagForm } from "./authoring-Bv-ExMUC.mjs";
|
|
7
7
|
import { a as flatPslModels, c as namespacePslExtensionBlocks } from "./psl-ast-CyvE6CR-.mjs";
|
|
8
|
+
import { l as printSyntax } from "./ast-helpers-CzydMPdh-Mi0SrZRa.mjs";
|
|
8
9
|
import { n as isPslIdentifier } from "./tokenizer-C-GTKKjR-B1vOzJy0.mjs";
|
|
9
|
-
import { D as TypesBlockAst, S as PathExprAst, T as TaggedLiteralExprAst, a as CompositeTypeDeclarationAst, d as IdentifierAst, g as ModelDeclarationAst, i as BooleanLiteralExprAst, l as FunctionCallAst, p as MixinDeclarationAst, t as ArrayLiteralAst, u as GenericBlockDeclarationAst, v as NamespaceDeclarationAst, w as StringLiteralExprAst, x as ObjectLiteralExprAst, y as NumberLiteralExprAst } from "./declarations-
|
|
10
|
+
import { D as TypesBlockAst, S as PathExprAst, T as TaggedLiteralExprAst, a as CompositeTypeDeclarationAst, c as FieldDeclarationAst, d as IdentifierAst, f as KeyValuePairAst, g as ModelDeclarationAst, h as ModelAttributeAst, i as BooleanLiteralExprAst, l as FunctionCallAst, p as MixinDeclarationAst, t as ArrayLiteralAst, u as GenericBlockDeclarationAst, v as NamespaceDeclarationAst, w as StringLiteralExprAst, x as ObjectLiteralExprAst, y as NumberLiteralExprAst } from "./declarations-DuSbyF44-Bee8mK-C.mjs";
|
|
10
11
|
import { a as mapPslDiagnostics, c as readResolvedAttributes, i as keywordPslSpan, l as readResolvedConstructorCall, n as diagnosticFromSpan, o as nodePslSpan, r as diagnosticSource, s as readResolvedAttribute, t as createPslDiagnosticCollector } from "./resolve-C8PUf8zv-QAvnPhCt.mjs";
|
|
11
|
-
//#region ../../../1-framework/2-authoring/psl-parser/dist/
|
|
12
|
+
//#region ../../../1-framework/2-authoring/psl-parser/dist/binder-DNpvbbBT.mjs
|
|
12
13
|
function* modelAttributeDescriptors(namespace) {
|
|
13
14
|
for (const value of Object.values(namespace)) {
|
|
14
15
|
if (isAuthoringModelAttributeDescriptor(value)) {
|
|
@@ -265,6 +266,12 @@ function namespaceMember(namespace, name) {
|
|
|
265
266
|
symbol: block,
|
|
266
267
|
namespace
|
|
267
268
|
};
|
|
269
|
+
const mixin = namespace.mixins[name];
|
|
270
|
+
if (mixin !== void 0) return {
|
|
271
|
+
kind: "mixin",
|
|
272
|
+
symbol: mixin,
|
|
273
|
+
namespace
|
|
274
|
+
};
|
|
268
275
|
}
|
|
269
276
|
var ContributedScope = class extends Scope {
|
|
270
277
|
#registry;
|
|
@@ -308,6 +315,11 @@ var DocumentScope = class extends Scope {
|
|
|
308
315
|
kind: "block",
|
|
309
316
|
symbol: block
|
|
310
317
|
};
|
|
318
|
+
const mixin = records.mixins[name];
|
|
319
|
+
if (mixin !== void 0) return {
|
|
320
|
+
kind: "mixin",
|
|
321
|
+
symbol: mixin
|
|
322
|
+
};
|
|
311
323
|
const namespace = records.namespaces[name];
|
|
312
324
|
if (namespace !== void 0) return {
|
|
313
325
|
kind: "namespace",
|
|
@@ -317,7 +329,7 @@ var DocumentScope = class extends Scope {
|
|
|
317
329
|
}
|
|
318
330
|
ownNames() {
|
|
319
331
|
const records = this.#records;
|
|
320
|
-
return recordNames(records.models, records.compositeTypes, records.namedTypes, records.blocks, records.namespaces);
|
|
332
|
+
return recordNames(records.models, records.compositeTypes, records.namedTypes, records.blocks, records.mixins, records.namespaces);
|
|
321
333
|
}
|
|
322
334
|
};
|
|
323
335
|
var NamespaceScope = class extends Scope {
|
|
@@ -331,7 +343,7 @@ var NamespaceScope = class extends Scope {
|
|
|
331
343
|
}
|
|
332
344
|
ownNames() {
|
|
333
345
|
const namespace = this.#namespace;
|
|
334
|
-
return recordNames(namespace.models, namespace.compositeTypes, namespace.blocks);
|
|
346
|
+
return recordNames(namespace.models, namespace.compositeTypes, namespace.blocks, namespace.mixins);
|
|
335
347
|
}
|
|
336
348
|
};
|
|
337
349
|
function contributedScope(registry) {
|
|
@@ -366,6 +378,355 @@ function lookupMember(qualifier, name) {
|
|
|
366
378
|
}
|
|
367
379
|
return namespaceMember(qualifier.symbol, name);
|
|
368
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* Owns duplicate-declaration detection for all PSL scopes; downstream consumers
|
|
383
|
+
* should consume first-wins symbols rather than re-emitting duplicate diagnostics.
|
|
384
|
+
*/
|
|
385
|
+
function buildSymbolTable(options) {
|
|
386
|
+
const { documents, sources } = options;
|
|
387
|
+
const diagnostics = [];
|
|
388
|
+
const namespaces = Object.create(null);
|
|
389
|
+
const namedTypes = Object.create(null);
|
|
390
|
+
const blocks = Object.create(null);
|
|
391
|
+
const models = Object.create(null);
|
|
392
|
+
const compositeTypes = Object.create(null);
|
|
393
|
+
const mixins = Object.create(null);
|
|
394
|
+
const topLevelNames = /* @__PURE__ */ new Set();
|
|
395
|
+
for (const document of documents) {
|
|
396
|
+
const sourceFile = sources.sourceFileFor(document.syntax);
|
|
397
|
+
const claim = (taken, name) => {
|
|
398
|
+
const text = name?.name();
|
|
399
|
+
if (text === void 0) return void 0;
|
|
400
|
+
if (taken.has(text)) {
|
|
401
|
+
const range = nameRange(name, sources);
|
|
402
|
+
if (range) diagnostics.push({
|
|
403
|
+
code: "PSL_DUPLICATE_DECLARATION",
|
|
404
|
+
message: `Duplicate declaration of "${text}"`,
|
|
405
|
+
filename: sourceFile.filename,
|
|
406
|
+
range
|
|
407
|
+
});
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
taken.add(text);
|
|
411
|
+
return text;
|
|
412
|
+
};
|
|
413
|
+
for (const declaration of document.declarations()) if (declaration instanceof ModelDeclarationAst) {
|
|
414
|
+
const name = claim(topLevelNames, declaration.name());
|
|
415
|
+
if (name !== void 0) models[name] = buildModel(name, declaration, sources, diagnostics);
|
|
416
|
+
} else if (declaration instanceof CompositeTypeDeclarationAst) {
|
|
417
|
+
const name = claim(topLevelNames, declaration.name());
|
|
418
|
+
if (name !== void 0) compositeTypes[name] = buildCompositeType(name, declaration, sources, diagnostics);
|
|
419
|
+
} else if (declaration instanceof GenericBlockDeclarationAst) {
|
|
420
|
+
const name = claim(topLevelNames, declaration.name());
|
|
421
|
+
if (name !== void 0) blocks[name] = buildBlock(name, declaration, sources);
|
|
422
|
+
} else if (declaration instanceof MixinDeclarationAst) {
|
|
423
|
+
const name = claim(topLevelNames, declaration.name());
|
|
424
|
+
if (name !== void 0) mixins[name] = buildMixin(name, declaration, sources, diagnostics);
|
|
425
|
+
} else if (declaration instanceof NamespaceDeclarationAst) {
|
|
426
|
+
const declaredName = declaration.name()?.name();
|
|
427
|
+
if (declaredName === void 0) continue;
|
|
428
|
+
let namespace = namespaces[declaredName];
|
|
429
|
+
if (namespace === void 0) {
|
|
430
|
+
const name = claim(topLevelNames, declaration.name());
|
|
431
|
+
if (name === void 0) continue;
|
|
432
|
+
namespace = {
|
|
433
|
+
kind: "namespace",
|
|
434
|
+
name,
|
|
435
|
+
declarations: [{
|
|
436
|
+
node: declaration,
|
|
437
|
+
span: nodePslSpan(declaration.syntax, sources)
|
|
438
|
+
}],
|
|
439
|
+
models: Object.create(null),
|
|
440
|
+
compositeTypes: Object.create(null),
|
|
441
|
+
blocks: Object.create(null),
|
|
442
|
+
mixins: Object.create(null)
|
|
443
|
+
};
|
|
444
|
+
namespaces[name] = namespace;
|
|
445
|
+
} else namespace.declarations.push({
|
|
446
|
+
node: declaration,
|
|
447
|
+
span: nodePslSpan(declaration.syntax, sources)
|
|
448
|
+
});
|
|
449
|
+
extendNamespace(namespace, declaration, diagnostics, sources);
|
|
450
|
+
} else if (declaration instanceof TypesBlockAst) for (const binding of declaration.declarations()) {
|
|
451
|
+
const name = claim(topLevelNames, binding.name());
|
|
452
|
+
if (name === void 0) continue;
|
|
453
|
+
const resolved = resolveNamedTypeBinding(binding, sources);
|
|
454
|
+
namedTypes[name] = {
|
|
455
|
+
kind: "namedType",
|
|
456
|
+
name,
|
|
457
|
+
node: binding,
|
|
458
|
+
span: nodePslSpan(binding.syntax, sources),
|
|
459
|
+
...resolved
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
symbolTable: { topLevel: {
|
|
465
|
+
namespaces,
|
|
466
|
+
namedTypes,
|
|
467
|
+
blocks,
|
|
468
|
+
models,
|
|
469
|
+
compositeTypes,
|
|
470
|
+
mixins
|
|
471
|
+
} },
|
|
472
|
+
diagnostics
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function buildModel(name, node, sources, diagnostics) {
|
|
476
|
+
return {
|
|
477
|
+
kind: "model",
|
|
478
|
+
name,
|
|
479
|
+
node,
|
|
480
|
+
span: nodePslSpan(node.syntax, sources),
|
|
481
|
+
fields: buildFields(name, node.fields(), sources, diagnostics),
|
|
482
|
+
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function buildCompositeType(name, node, sources, diagnostics) {
|
|
486
|
+
return {
|
|
487
|
+
kind: "compositeType",
|
|
488
|
+
name,
|
|
489
|
+
node,
|
|
490
|
+
span: nodePslSpan(node.syntax, sources),
|
|
491
|
+
fields: buildFields(name, node.fields(), sources, diagnostics),
|
|
492
|
+
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function buildBlock(name, node, sources) {
|
|
496
|
+
return {
|
|
497
|
+
kind: "block",
|
|
498
|
+
name,
|
|
499
|
+
keyword: node.keyword()?.text ?? "",
|
|
500
|
+
node,
|
|
501
|
+
span: nodePslSpan(node.syntax, sources),
|
|
502
|
+
entries: Array.from(node.entries()),
|
|
503
|
+
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const FIELD_BLOCK_KEYWORDS = /* @__PURE__ */ new Set(["model", "type"]);
|
|
507
|
+
function buildMixin(name, node, sources, diagnostics) {
|
|
508
|
+
const keyword = node.keyword()?.text ?? "";
|
|
509
|
+
const hasFields = FIELD_BLOCK_KEYWORDS.has(keyword);
|
|
510
|
+
return {
|
|
511
|
+
kind: "mixin",
|
|
512
|
+
name,
|
|
513
|
+
keyword,
|
|
514
|
+
node,
|
|
515
|
+
span: nodePslSpan(node.syntax, sources),
|
|
516
|
+
fields: hasFields ? buildFields(name, node.fields(), sources, diagnostics) : Object.create(null),
|
|
517
|
+
entries: hasFields ? [] : Array.from(node.entries()),
|
|
518
|
+
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function extendNamespace(namespace, node, diagnostics, sources) {
|
|
522
|
+
const { models, compositeTypes, blocks, mixins } = namespace;
|
|
523
|
+
for (const member of node.declarations()) {
|
|
524
|
+
const memberName = member.name()?.name();
|
|
525
|
+
if (memberName === void 0) continue;
|
|
526
|
+
if (Object.hasOwn(models, memberName) || Object.hasOwn(compositeTypes, memberName) || Object.hasOwn(blocks, memberName) || Object.hasOwn(mixins, memberName)) {
|
|
527
|
+
const range = nameRange(member.name(), sources);
|
|
528
|
+
if (range) diagnostics.push({
|
|
529
|
+
code: "PSL_DUPLICATE_DECLARATION",
|
|
530
|
+
message: `Duplicate declaration of "${memberName}"`,
|
|
531
|
+
filename: sources.sourceFileFor(member.syntax).filename,
|
|
532
|
+
range
|
|
533
|
+
});
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (member instanceof ModelDeclarationAst) models[memberName] = buildModel(memberName, member, sources, diagnostics);
|
|
537
|
+
else if (member instanceof CompositeTypeDeclarationAst) compositeTypes[memberName] = buildCompositeType(memberName, member, sources, diagnostics);
|
|
538
|
+
else if (member instanceof GenericBlockDeclarationAst) blocks[memberName] = buildBlock(memberName, member, sources);
|
|
539
|
+
else if (member instanceof MixinDeclarationAst) mixins[memberName] = buildMixin(memberName, member, sources, diagnostics);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
function placeMixinMembers(input) {
|
|
543
|
+
const { topLevel } = input.symbolTable;
|
|
544
|
+
const diagnostics = [];
|
|
545
|
+
for (const records of [topLevel, ...Object.values(topLevel.namespaces)]) {
|
|
546
|
+
for (const symbol of Object.values(records.models)) placeFields(symbol, input, diagnostics);
|
|
547
|
+
for (const symbol of Object.values(records.compositeTypes)) placeFields(symbol, input, diagnostics);
|
|
548
|
+
for (const symbol of Object.values(records.blocks)) placeEntries(symbol, input, diagnostics);
|
|
549
|
+
}
|
|
550
|
+
return diagnostics;
|
|
551
|
+
}
|
|
552
|
+
function includesMixin(symbol, input) {
|
|
553
|
+
for (const inclusion of symbol.node.inclusions()) if (input.mixinOf(inclusion) !== void 0) return true;
|
|
554
|
+
return false;
|
|
555
|
+
}
|
|
556
|
+
function inclusionDiagnostic(code, message, inclusion, sources) {
|
|
557
|
+
return {
|
|
558
|
+
code,
|
|
559
|
+
message,
|
|
560
|
+
filename: sources.sourceFileFor(inclusion.syntax).filename,
|
|
561
|
+
range: nodeRange(inclusion.syntax, sources)
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function mixinToPlace(inclusion, symbol, placed, input, diagnostics) {
|
|
565
|
+
const mixin = input.mixinOf(inclusion);
|
|
566
|
+
if (mixin === void 0) return void 0;
|
|
567
|
+
if (placed.has(mixin)) {
|
|
568
|
+
diagnostics.push(inclusionDiagnostic(symbol.kind === "block" ? "PSL_INVALID_EXTENSION_BLOCK_MEMBER" : "PSL_INVALID_MODEL_MEMBER", `Mixin "${mixin.name}" is already included in this block`, inclusion, input.sources));
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
placed.add(mixin);
|
|
572
|
+
return mixin;
|
|
573
|
+
}
|
|
574
|
+
function alreadyProvided(mixin, member, symbol, inclusion, sources) {
|
|
575
|
+
return inclusionDiagnostic("PSL_DUPLICATE_DECLARATION", `Mixin "${mixin.name}" provides "${member}", which "${symbol.name}" already has`, inclusion, sources);
|
|
576
|
+
}
|
|
577
|
+
function writtenAttributes(symbol) {
|
|
578
|
+
return new Map(symbol.attributes.map((attribute) => [attribute.node.syntax, attribute]));
|
|
579
|
+
}
|
|
580
|
+
function placeFields(symbol, input, diagnostics) {
|
|
581
|
+
if (!includesMixin(symbol, input)) return;
|
|
582
|
+
const { sources } = input;
|
|
583
|
+
const ownFields = new Map(Object.values(symbol.fields).map((field) => [field.node.syntax, field]));
|
|
584
|
+
const ownAttributes = writtenAttributes(symbol);
|
|
585
|
+
const fields = Object.create(null);
|
|
586
|
+
const attributes = [];
|
|
587
|
+
const placed = /* @__PURE__ */ new Set();
|
|
588
|
+
for (const member of symbol.node.members()) if (member instanceof FieldDeclarationAst) {
|
|
589
|
+
const field = ownFields.get(member.syntax);
|
|
590
|
+
if (field === void 0) continue;
|
|
591
|
+
if (Object.hasOwn(fields, field.name)) {
|
|
592
|
+
const diagnostic = duplicateDeclaration(field.name, member.name(), sources);
|
|
593
|
+
if (diagnostic !== void 0) diagnostics.push(diagnostic);
|
|
594
|
+
} else fields[field.name] = field;
|
|
595
|
+
} else if (member instanceof ModelAttributeAst) {
|
|
596
|
+
const attribute = ownAttributes.get(member.syntax);
|
|
597
|
+
if (attribute !== void 0) attributes.push(attribute);
|
|
598
|
+
} else {
|
|
599
|
+
const mixin = mixinToPlace(member, symbol, placed, input, diagnostics);
|
|
600
|
+
if (mixin === void 0) continue;
|
|
601
|
+
for (const field of Object.values(mixin.fields)) if (Object.hasOwn(fields, field.name)) diagnostics.push(alreadyProvided(mixin, field.name, symbol, member, sources));
|
|
602
|
+
else fields[field.name] = field;
|
|
603
|
+
attributes.push(...mixin.attributes);
|
|
604
|
+
}
|
|
605
|
+
symbol.fields = fields;
|
|
606
|
+
symbol.attributes = attributes;
|
|
607
|
+
}
|
|
608
|
+
function placeEntries(symbol, input, diagnostics) {
|
|
609
|
+
if (!includesMixin(symbol, input)) return;
|
|
610
|
+
const ownAttributes = writtenAttributes(symbol);
|
|
611
|
+
const entries = [];
|
|
612
|
+
const attributes = [];
|
|
613
|
+
const placed = /* @__PURE__ */ new Set();
|
|
614
|
+
for (const member of symbol.node.members()) if (member instanceof KeyValuePairAst) entries.push(member);
|
|
615
|
+
else if (member instanceof ModelAttributeAst) {
|
|
616
|
+
const attribute = ownAttributes.get(member.syntax);
|
|
617
|
+
if (attribute !== void 0) attributes.push(attribute);
|
|
618
|
+
} else {
|
|
619
|
+
const mixin = mixinToPlace(member, symbol, placed, input, diagnostics);
|
|
620
|
+
if (mixin === void 0) continue;
|
|
621
|
+
const present = new Set(entries.map((entry) => entry.key()?.name()));
|
|
622
|
+
for (const entry of mixin.entries) {
|
|
623
|
+
const key = entry.key()?.name();
|
|
624
|
+
if (key !== void 0 && present.has(key)) diagnostics.push(alreadyProvided(mixin, key, symbol, member, input.sources));
|
|
625
|
+
else entries.push(entry);
|
|
626
|
+
}
|
|
627
|
+
attributes.push(...mixin.attributes);
|
|
628
|
+
}
|
|
629
|
+
symbol.entries = entries;
|
|
630
|
+
symbol.attributes = attributes;
|
|
631
|
+
}
|
|
632
|
+
function duplicateDeclaration(name, nameNode, sources) {
|
|
633
|
+
const range = nameRange(nameNode, sources);
|
|
634
|
+
if (nameNode === void 0 || range === void 0) return void 0;
|
|
635
|
+
return {
|
|
636
|
+
code: "PSL_DUPLICATE_DECLARATION",
|
|
637
|
+
message: `Duplicate declaration of "${name}"`,
|
|
638
|
+
filename: sources.sourceFileFor(nameNode.syntax).filename,
|
|
639
|
+
range
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function buildFields(ownerName, fields, sources, diagnostics) {
|
|
643
|
+
const result = Object.create(null);
|
|
644
|
+
for (const field of fields) {
|
|
645
|
+
const nameNode = field.name();
|
|
646
|
+
const name = nameNode?.name();
|
|
647
|
+
if (name === void 0) continue;
|
|
648
|
+
if (Object.hasOwn(result, name)) {
|
|
649
|
+
const diagnostic = duplicateDeclaration(name, nameNode, sources);
|
|
650
|
+
if (diagnostic !== void 0) diagnostics.push(diagnostic);
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
result[name] = buildField(ownerName, name, field, sources, diagnostics);
|
|
654
|
+
}
|
|
655
|
+
return result;
|
|
656
|
+
}
|
|
657
|
+
function buildField(ownerName, name, node, sources, diagnostics) {
|
|
658
|
+
const attributes = readResolvedAttributes(node.attributes(), sources);
|
|
659
|
+
const span = nodePslSpan(node.syntax, sources);
|
|
660
|
+
const annotation = node.typeAnnotation();
|
|
661
|
+
const typeName = annotation?.name();
|
|
662
|
+
if (typeName?.isOverQualified()) {
|
|
663
|
+
const path = typeName.path();
|
|
664
|
+
diagnostics.push({
|
|
665
|
+
code: "PSL_INVALID_QUALIFIED_TYPE",
|
|
666
|
+
message: `Field "${ownerName}.${name}" has an invalid qualified type "${path.join(".")}"; use at most one namespace qualifier (e.g. "ns.TypeName")`,
|
|
667
|
+
filename: sources.sourceFileFor(typeName.syntax).filename,
|
|
668
|
+
range: nodeRange(typeName.syntax, sources)
|
|
669
|
+
});
|
|
670
|
+
return {
|
|
671
|
+
kind: "field",
|
|
672
|
+
name,
|
|
673
|
+
node,
|
|
674
|
+
span,
|
|
675
|
+
typeName: path[path.length - 1] ?? "",
|
|
676
|
+
optional: false,
|
|
677
|
+
list: false,
|
|
678
|
+
elementOptional: false,
|
|
679
|
+
malformedType: true,
|
|
680
|
+
attributes
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
const typeConstructor = annotation?.isConstructor() ? readResolvedConstructorCall(annotation, sources) : void 0;
|
|
684
|
+
const typeNamespaceId = typeName?.namespace()?.name();
|
|
685
|
+
const typeContractSpaceId = typeName?.space()?.name();
|
|
686
|
+
return {
|
|
687
|
+
kind: "field",
|
|
688
|
+
name,
|
|
689
|
+
node,
|
|
690
|
+
span,
|
|
691
|
+
typeName: typeName?.identifier()?.name() ?? "",
|
|
692
|
+
...typeNamespaceId !== void 0 ? { typeNamespaceId } : {},
|
|
693
|
+
...typeContractSpaceId !== void 0 ? { typeContractSpaceId } : {},
|
|
694
|
+
optional: annotation?.isOptional() ?? false,
|
|
695
|
+
list: annotation?.isList() ?? false,
|
|
696
|
+
elementOptional: annotation?.isElementOptional() ?? false,
|
|
697
|
+
...typeConstructor !== void 0 ? { typeConstructor } : {},
|
|
698
|
+
attributes
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
function resolveNamedTypeBinding(node, sources) {
|
|
702
|
+
const annotation = node.typeAnnotation();
|
|
703
|
+
const isConstructor = annotation?.isConstructor() ?? false;
|
|
704
|
+
const baseType = annotation?.name()?.identifier()?.name();
|
|
705
|
+
const typeConstructor = readResolvedConstructorCall(annotation, sources);
|
|
706
|
+
return {
|
|
707
|
+
isConstructor,
|
|
708
|
+
...!isConstructor && baseType !== void 0 ? { baseType } : {},
|
|
709
|
+
...typeConstructor !== void 0 ? { typeConstructor } : {},
|
|
710
|
+
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function nameRange(name, sources) {
|
|
714
|
+
if (name === void 0) return void 0;
|
|
715
|
+
const sourceFile = sources.sourceFileFor(name.syntax);
|
|
716
|
+
for (const token of name.syntax.tokens()) if (token.kind === "Ident") return {
|
|
717
|
+
start: sourceFile.positionAt(token.offset),
|
|
718
|
+
end: sourceFile.positionAt(token.offset + token.text.length)
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
function nodeRange(node, sources) {
|
|
722
|
+
const sourceFile = sources.sourceFileFor(node);
|
|
723
|
+
const start = node.offset;
|
|
724
|
+
const end = start + node.green.textLength;
|
|
725
|
+
return {
|
|
726
|
+
start: sourceFile.positionAt(start),
|
|
727
|
+
end: sourceFile.positionAt(end)
|
|
728
|
+
};
|
|
729
|
+
}
|
|
369
730
|
const PSL_UNRESOLVED_REFERENCE = "PSL_UNRESOLVED_REFERENCE";
|
|
370
731
|
function typeReferenceNode(symbol) {
|
|
371
732
|
return symbol.node.typeAnnotation()?.name()?.syntax;
|
|
@@ -413,17 +774,33 @@ var ScopeStack = class {
|
|
|
413
774
|
this.#scopes.pop();
|
|
414
775
|
}
|
|
415
776
|
};
|
|
416
|
-
|
|
777
|
+
const FIELD_MIXIN_KEYWORDS = /* @__PURE__ */ new Set(["model", "type"]);
|
|
778
|
+
function hasFields(mixin) {
|
|
779
|
+
return FIELD_MIXIN_KEYWORDS.has(mixin.keyword);
|
|
780
|
+
}
|
|
781
|
+
function walkFieldOwners(symbolTable, stack, binder, visit) {
|
|
417
782
|
const { topLevel } = symbolTable;
|
|
418
|
-
|
|
419
|
-
|
|
783
|
+
const visitAll = (records, namespace) => {
|
|
784
|
+
for (const entity of Object.values(records.models)) visit(entity, namespace);
|
|
785
|
+
for (const entity of Object.values(records.compositeTypes)) visit(entity, namespace);
|
|
786
|
+
for (const mixin of Object.values(records.mixins)) if (hasFields(mixin)) visit(mixin, namespace);
|
|
787
|
+
};
|
|
788
|
+
visitAll(topLevel);
|
|
420
789
|
for (const namespace of Object.values(topLevel.namespaces)) {
|
|
421
790
|
stack.push(binder.scopeAt(namespace.declarations[0].node.syntax));
|
|
422
|
-
|
|
423
|
-
for (const entity of Object.values(namespace.compositeTypes)) visit(entity, namespace);
|
|
791
|
+
visitAll(namespace, namespace);
|
|
424
792
|
stack.pop();
|
|
425
793
|
}
|
|
426
794
|
}
|
|
795
|
+
function isWrittenIn(member, holder) {
|
|
796
|
+
return member.parent === holder.node.syntax;
|
|
797
|
+
}
|
|
798
|
+
function ownFields(owner) {
|
|
799
|
+
return Object.values(owner.fields).filter((field) => isWrittenIn(field.node.syntax, owner));
|
|
800
|
+
}
|
|
801
|
+
function ownAttributes(holder) {
|
|
802
|
+
return holder.attributes.filter((attribute) => isWrittenIn(attribute.node.syntax, holder));
|
|
803
|
+
}
|
|
427
804
|
function declarationResolution(entity, namespace) {
|
|
428
805
|
return entity.kind === "model" ? {
|
|
429
806
|
kind: "model",
|
|
@@ -490,6 +867,14 @@ function bind(options) {
|
|
|
490
867
|
symbol
|
|
491
868
|
});
|
|
492
869
|
}
|
|
870
|
+
for (const symbol of Object.values(symbolTable.topLevel.mixins)) {
|
|
871
|
+
declarations.set(symbol.node.syntax, symbol);
|
|
872
|
+
const declaredName = symbol.node.name()?.syntax;
|
|
873
|
+
if (declaredName !== void 0) references.set(declaredName, {
|
|
874
|
+
kind: "mixin",
|
|
875
|
+
symbol
|
|
876
|
+
});
|
|
877
|
+
}
|
|
493
878
|
for (const namespace of Object.values(symbolTable.topLevel.namespaces)) {
|
|
494
879
|
const scope = namespaceScope(namespace, document);
|
|
495
880
|
for (const declaration of namespace.declarations) {
|
|
@@ -510,12 +895,37 @@ function bind(options) {
|
|
|
510
895
|
namespace
|
|
511
896
|
});
|
|
512
897
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
898
|
+
for (const symbol of Object.values(namespace.mixins)) {
|
|
899
|
+
declarations.set(symbol.node.syntax, symbol);
|
|
900
|
+
const declaredName = symbol.node.name()?.syntax;
|
|
901
|
+
if (declaredName !== void 0) references.set(declaredName, {
|
|
902
|
+
kind: "mixin",
|
|
903
|
+
symbol,
|
|
904
|
+
namespace
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
const included = /* @__PURE__ */ new Map();
|
|
909
|
+
const inclusionContext = {
|
|
910
|
+
sources,
|
|
911
|
+
references,
|
|
912
|
+
diagnostics,
|
|
913
|
+
included
|
|
914
|
+
};
|
|
915
|
+
bindInclusions(symbolTable.topLevel, document, inclusionContext);
|
|
916
|
+
for (const namespace of Object.values(symbolTable.topLevel.namespaces)) bindInclusions(namespace, binder.scopeAt(namespace.declarations[0].node.syntax), inclusionContext);
|
|
917
|
+
diagnostics.push(...placeMixinMembers({
|
|
918
|
+
symbolTable,
|
|
919
|
+
sources,
|
|
920
|
+
mixinOf: (inclusion) => included.get(inclusion.syntax)
|
|
921
|
+
}));
|
|
922
|
+
walkFieldOwners(symbolTable, stack, binder, (entity, namespace) => {
|
|
923
|
+
if (entity.kind !== "mixin") {
|
|
924
|
+
declarations.set(entity.node.syntax, entity);
|
|
925
|
+
const declaredName = entity.node.name()?.syntax;
|
|
926
|
+
if (declaredName !== void 0) references.set(declaredName, declarationResolution(entity, namespace));
|
|
927
|
+
}
|
|
928
|
+
for (const field of ownFields(entity)) {
|
|
519
929
|
declarations.set(field.node.syntax, field);
|
|
520
930
|
const fieldName = field.node.name()?.syntax;
|
|
521
931
|
if (fieldName !== void 0) references.set(fieldName, {
|
|
@@ -550,7 +960,7 @@ function bind(options) {
|
|
|
550
960
|
});
|
|
551
961
|
}
|
|
552
962
|
});
|
|
553
|
-
|
|
963
|
+
walkFieldOwners(symbolTable, stack, binder, (entity) => {
|
|
554
964
|
const context = {
|
|
555
965
|
owner: entity,
|
|
556
966
|
scope: stack.current(),
|
|
@@ -560,17 +970,17 @@ function bind(options) {
|
|
|
560
970
|
sources,
|
|
561
971
|
describeUnsupportedAttribute
|
|
562
972
|
};
|
|
563
|
-
const specContext = entity.kind === "model" ? {
|
|
973
|
+
const specContext = entity.kind === "model" || entity.kind === "mixin" && entity.keyword === "model" ? {
|
|
564
974
|
symbols: symbolTable,
|
|
565
975
|
model: entity,
|
|
566
976
|
defaultFunctionRegistry,
|
|
567
977
|
dataTypes
|
|
568
978
|
} : void 0;
|
|
569
|
-
bindAttributes(entity, entity
|
|
979
|
+
bindAttributes(entity, ownAttributes(entity), attributeSpecs.model, (factory) => specContext === void 0 ? void 0 : factory(specContext), {
|
|
570
980
|
...context,
|
|
571
981
|
field: void 0
|
|
572
982
|
});
|
|
573
|
-
for (const field of
|
|
983
|
+
for (const field of ownFields(entity)) bindAttributes(field, field.attributes, attributeSpecs.field, (factory) => {
|
|
574
984
|
if (specContext === void 0) return void 0;
|
|
575
985
|
const node = typeReferenceNode(field);
|
|
576
986
|
const typeResolution = node === void 0 ? void 0 : references.get(node);
|
|
@@ -592,17 +1002,22 @@ function bind(options) {
|
|
|
592
1002
|
references,
|
|
593
1003
|
diagnostics
|
|
594
1004
|
};
|
|
595
|
-
const bindBlocks = (
|
|
1005
|
+
const bindBlocks = (records) => {
|
|
596
1006
|
const context = {
|
|
597
1007
|
...blockContext,
|
|
598
1008
|
scope: stack.current()
|
|
599
1009
|
};
|
|
600
|
-
for (const block of Object.values(blocks)) bindBlock(
|
|
601
|
-
|
|
602
|
-
|
|
1010
|
+
for (const block of Object.values(records.blocks)) bindBlock({
|
|
1011
|
+
keyword: block.keyword,
|
|
1012
|
+
entries: block.entries.filter((entry) => isWrittenIn(entry.syntax, block)),
|
|
1013
|
+
attributes: ownAttributes(block)
|
|
1014
|
+
}, context);
|
|
1015
|
+
for (const mixin of Object.values(records.mixins)) if (!hasFields(mixin)) bindBlock(mixin, context);
|
|
1016
|
+
};
|
|
1017
|
+
bindBlocks(symbolTable.topLevel);
|
|
603
1018
|
for (const namespace of Object.values(symbolTable.topLevel.namespaces)) {
|
|
604
1019
|
stack.push(binder.scopeAt(namespace.declarations[0].node.syntax));
|
|
605
|
-
bindBlocks(namespace
|
|
1020
|
+
bindBlocks(namespace);
|
|
606
1021
|
stack.pop();
|
|
607
1022
|
}
|
|
608
1023
|
return {
|
|
@@ -610,6 +1025,49 @@ function bind(options) {
|
|
|
610
1025
|
diagnostics
|
|
611
1026
|
};
|
|
612
1027
|
}
|
|
1028
|
+
function bindInclusions(records, scope, ctx) {
|
|
1029
|
+
const report = (code, message, inclusion) => {
|
|
1030
|
+
ctx.diagnostics.push({
|
|
1031
|
+
code,
|
|
1032
|
+
message,
|
|
1033
|
+
...diagnosticSource(ctx.sources, inclusion.syntax).at()
|
|
1034
|
+
});
|
|
1035
|
+
};
|
|
1036
|
+
for (const mixin of Object.values(records.mixins)) for (const inclusion of mixin.node.inclusions()) {
|
|
1037
|
+
if (inclusion.name() === void 0) continue;
|
|
1038
|
+
report(hasFields(mixin) ? "PSL_INVALID_MODEL_MEMBER" : "PSL_INVALID_EXTENSION_BLOCK_MEMBER", "A mixin cannot include another mixin", inclusion);
|
|
1039
|
+
}
|
|
1040
|
+
const holders = [
|
|
1041
|
+
...Object.values(records.models),
|
|
1042
|
+
...Object.values(records.compositeTypes),
|
|
1043
|
+
...Object.values(records.blocks)
|
|
1044
|
+
];
|
|
1045
|
+
for (const holder of holders) {
|
|
1046
|
+
const keyword = holder.kind === "model" ? "model" : holder.kind === "compositeType" ? "type" : holder.keyword;
|
|
1047
|
+
for (const inclusion of holder.node.inclusions()) {
|
|
1048
|
+
const reference = inclusion.name();
|
|
1049
|
+
const outcome = resolveTypeReference(reference, scope, ctx.references);
|
|
1050
|
+
if (reference === void 0 || outcome === void 0) continue;
|
|
1051
|
+
const { resolution } = outcome;
|
|
1052
|
+
if (resolution.kind !== "mixin") {
|
|
1053
|
+
const name = printSyntax(reference.syntax);
|
|
1054
|
+
ctx.references.set(reference.syntax, {
|
|
1055
|
+
kind: "unresolved",
|
|
1056
|
+
name
|
|
1057
|
+
});
|
|
1058
|
+
report(PSL_UNRESOLVED_REFERENCE, `Cannot find mixin "${name}"`, inclusion);
|
|
1059
|
+
continue;
|
|
1060
|
+
}
|
|
1061
|
+
ctx.references.set(reference.syntax, resolution);
|
|
1062
|
+
const mixin = resolution.symbol;
|
|
1063
|
+
if (mixin.keyword === keyword) {
|
|
1064
|
+
ctx.included.set(inclusion.syntax, mixin);
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
report(holder.kind === "block" ? "PSL_INVALID_EXTENSION_BLOCK_MEMBER" : "PSL_INVALID_MODEL_MEMBER", `Mixin "${mixin.name}" is for "${mixin.keyword}" blocks, not "${keyword}" blocks`, inclusion);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
613
1071
|
function bindBlock(block, ctx) {
|
|
614
1072
|
const descriptor = findBlockDescriptor(ctx.pslBlockDescriptors, block.keyword);
|
|
615
1073
|
if (descriptor === void 0) return;
|
|
@@ -1062,11 +1520,11 @@ function resolveTypeReference(reference, scope, references, describeUnresolved)
|
|
|
1062
1520
|
message: found.badQualifier,
|
|
1063
1521
|
name: found.qualifier
|
|
1064
1522
|
};
|
|
1065
|
-
if (found.kind === "namespace" || found.kind === "contributedNamespace") {
|
|
1523
|
+
if (found.kind === "namespace" || found.kind === "contributedNamespace" || found.kind === "mixin") {
|
|
1066
1524
|
const written = namespaceId === void 0 ? name : `${namespaceId}.${name}`;
|
|
1067
1525
|
return {
|
|
1068
1526
|
resolution: found,
|
|
1069
|
-
message: `"${written}" is a namespace; a type reference must name a model, composite type, enum, or named type`,
|
|
1527
|
+
message: `"${written}" is a ${found.kind === "mixin" ? "mixin" : "namespace"}; a type reference must name a model, composite type, enum, or named type`,
|
|
1070
1528
|
name: written
|
|
1071
1529
|
};
|
|
1072
1530
|
}
|
|
@@ -1092,278 +1550,6 @@ function describeQualifier(resolution) {
|
|
|
1092
1550
|
function own(record, name) {
|
|
1093
1551
|
return Object.hasOwn(record, name) ? record[name] : void 0;
|
|
1094
1552
|
}
|
|
1095
|
-
/**
|
|
1096
|
-
* Owns duplicate-declaration detection for all PSL scopes; downstream consumers
|
|
1097
|
-
* should consume first-wins symbols rather than re-emitting duplicate diagnostics.
|
|
1098
|
-
*/
|
|
1099
|
-
function buildSymbolTable(options) {
|
|
1100
|
-
const { documents, sources } = options;
|
|
1101
|
-
const diagnostics = [];
|
|
1102
|
-
const namespaces = Object.create(null);
|
|
1103
|
-
const namedTypes = Object.create(null);
|
|
1104
|
-
const blocks = Object.create(null);
|
|
1105
|
-
const models = Object.create(null);
|
|
1106
|
-
const compositeTypes = Object.create(null);
|
|
1107
|
-
const topLevelNames = /* @__PURE__ */ new Set();
|
|
1108
|
-
for (const document of documents) {
|
|
1109
|
-
const sourceFile = sources.sourceFileFor(document.syntax);
|
|
1110
|
-
const claim = (taken, name) => {
|
|
1111
|
-
const text = name?.name();
|
|
1112
|
-
if (text === void 0) return void 0;
|
|
1113
|
-
if (taken.has(text)) {
|
|
1114
|
-
const range = nameRange(name, sources);
|
|
1115
|
-
if (range) diagnostics.push({
|
|
1116
|
-
code: "PSL_DUPLICATE_DECLARATION",
|
|
1117
|
-
message: `Duplicate declaration of "${text}"`,
|
|
1118
|
-
filename: sourceFile.filename,
|
|
1119
|
-
range
|
|
1120
|
-
});
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
taken.add(text);
|
|
1124
|
-
return text;
|
|
1125
|
-
};
|
|
1126
|
-
for (const declaration of document.declarations()) if (declaration instanceof ModelDeclarationAst) {
|
|
1127
|
-
const name = claim(topLevelNames, declaration.name());
|
|
1128
|
-
if (name !== void 0) models[name] = buildModel(name, declaration, sources, diagnostics);
|
|
1129
|
-
} else if (declaration instanceof CompositeTypeDeclarationAst) {
|
|
1130
|
-
const name = claim(topLevelNames, declaration.name());
|
|
1131
|
-
if (name !== void 0) compositeTypes[name] = buildCompositeType(name, declaration, sources, diagnostics);
|
|
1132
|
-
} else if (declaration instanceof GenericBlockDeclarationAst) {
|
|
1133
|
-
const name = claim(topLevelNames, declaration.name());
|
|
1134
|
-
if (name !== void 0) blocks[name] = buildBlock(name, declaration, sources);
|
|
1135
|
-
} else if (declaration instanceof NamespaceDeclarationAst) {
|
|
1136
|
-
const declaredName = declaration.name()?.name();
|
|
1137
|
-
if (declaredName === void 0) continue;
|
|
1138
|
-
let namespace = namespaces[declaredName];
|
|
1139
|
-
if (namespace === void 0) {
|
|
1140
|
-
const name = claim(topLevelNames, declaration.name());
|
|
1141
|
-
if (name === void 0) continue;
|
|
1142
|
-
namespace = {
|
|
1143
|
-
kind: "namespace",
|
|
1144
|
-
name,
|
|
1145
|
-
declarations: [{
|
|
1146
|
-
node: declaration,
|
|
1147
|
-
span: nodePslSpan(declaration.syntax, sources)
|
|
1148
|
-
}],
|
|
1149
|
-
models: Object.create(null),
|
|
1150
|
-
compositeTypes: Object.create(null),
|
|
1151
|
-
blocks: Object.create(null)
|
|
1152
|
-
};
|
|
1153
|
-
namespaces[name] = namespace;
|
|
1154
|
-
} else namespace.declarations.push({
|
|
1155
|
-
node: declaration,
|
|
1156
|
-
span: nodePslSpan(declaration.syntax, sources)
|
|
1157
|
-
});
|
|
1158
|
-
extendNamespace(namespace, declaration, diagnostics, sources);
|
|
1159
|
-
} else if (declaration instanceof TypesBlockAst) for (const binding of declaration.declarations()) {
|
|
1160
|
-
const name = claim(topLevelNames, binding.name());
|
|
1161
|
-
if (name === void 0) continue;
|
|
1162
|
-
const resolved = resolveNamedTypeBinding(binding, sources);
|
|
1163
|
-
namedTypes[name] = {
|
|
1164
|
-
kind: "namedType",
|
|
1165
|
-
name,
|
|
1166
|
-
node: binding,
|
|
1167
|
-
span: nodePslSpan(binding.syntax, sources),
|
|
1168
|
-
...resolved
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
reportMixins(document.declarations(), sources, diagnostics);
|
|
1172
|
-
}
|
|
1173
|
-
return {
|
|
1174
|
-
symbolTable: { topLevel: {
|
|
1175
|
-
namespaces,
|
|
1176
|
-
namedTypes,
|
|
1177
|
-
blocks,
|
|
1178
|
-
models,
|
|
1179
|
-
compositeTypes
|
|
1180
|
-
} },
|
|
1181
|
-
diagnostics
|
|
1182
|
-
};
|
|
1183
|
-
}
|
|
1184
|
-
function buildModel(name, node, sources, diagnostics) {
|
|
1185
|
-
return {
|
|
1186
|
-
kind: "model",
|
|
1187
|
-
name,
|
|
1188
|
-
node,
|
|
1189
|
-
span: nodePslSpan(node.syntax, sources),
|
|
1190
|
-
fields: buildFields(name, node.fields(), sources, diagnostics),
|
|
1191
|
-
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
function buildCompositeType(name, node, sources, diagnostics) {
|
|
1195
|
-
return {
|
|
1196
|
-
kind: "compositeType",
|
|
1197
|
-
name,
|
|
1198
|
-
node,
|
|
1199
|
-
span: nodePslSpan(node.syntax, sources),
|
|
1200
|
-
fields: buildFields(name, node.fields(), sources, diagnostics),
|
|
1201
|
-
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
1202
|
-
};
|
|
1203
|
-
}
|
|
1204
|
-
function buildBlock(name, node, sources) {
|
|
1205
|
-
return {
|
|
1206
|
-
kind: "block",
|
|
1207
|
-
name,
|
|
1208
|
-
keyword: node.keyword()?.text ?? "",
|
|
1209
|
-
node,
|
|
1210
|
-
span: nodePslSpan(node.syntax, sources),
|
|
1211
|
-
entries: Array.from(node.entries()),
|
|
1212
|
-
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
1213
|
-
};
|
|
1214
|
-
}
|
|
1215
|
-
function extendNamespace(namespace, node, diagnostics, sources) {
|
|
1216
|
-
const { models, compositeTypes, blocks } = namespace;
|
|
1217
|
-
for (const member of node.declarations()) {
|
|
1218
|
-
if (member instanceof MixinDeclarationAst) continue;
|
|
1219
|
-
const memberName = member.name()?.name();
|
|
1220
|
-
if (memberName === void 0) continue;
|
|
1221
|
-
if (Object.hasOwn(models, memberName) || Object.hasOwn(compositeTypes, memberName) || Object.hasOwn(blocks, memberName)) {
|
|
1222
|
-
const range = nameRange(member.name(), sources);
|
|
1223
|
-
if (range) diagnostics.push({
|
|
1224
|
-
code: "PSL_DUPLICATE_DECLARATION",
|
|
1225
|
-
message: `Duplicate declaration of "${memberName}"`,
|
|
1226
|
-
filename: sources.sourceFileFor(member.syntax).filename,
|
|
1227
|
-
range
|
|
1228
|
-
});
|
|
1229
|
-
continue;
|
|
1230
|
-
}
|
|
1231
|
-
if (member instanceof ModelDeclarationAst) models[memberName] = buildModel(memberName, member, sources, diagnostics);
|
|
1232
|
-
else if (member instanceof CompositeTypeDeclarationAst) compositeTypes[memberName] = buildCompositeType(memberName, member, sources, diagnostics);
|
|
1233
|
-
else if (member instanceof GenericBlockDeclarationAst) blocks[memberName] = buildBlock(memberName, member, sources);
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
const MIXINS_NOT_SUPPORTED = "Mixins are not supported yet";
|
|
1237
|
-
function reportMixins(declarations, sources, diagnostics) {
|
|
1238
|
-
for (const declaration of declarations) {
|
|
1239
|
-
if (declaration instanceof NamespaceDeclarationAst) {
|
|
1240
|
-
reportMixins(declaration.declarations(), sources, diagnostics);
|
|
1241
|
-
continue;
|
|
1242
|
-
}
|
|
1243
|
-
if (declaration instanceof TypesBlockAst) continue;
|
|
1244
|
-
if (declaration instanceof MixinDeclarationAst) {
|
|
1245
|
-
const range = nameRange(declaration.name(), sources) ?? mixinKeywordRange(declaration, sources);
|
|
1246
|
-
if (range !== void 0) diagnostics.push({
|
|
1247
|
-
code: "PSL_INVALID_DECLARATION",
|
|
1248
|
-
message: MIXINS_NOT_SUPPORTED,
|
|
1249
|
-
filename: sources.sourceFileFor(declaration.syntax).filename,
|
|
1250
|
-
range
|
|
1251
|
-
});
|
|
1252
|
-
}
|
|
1253
|
-
for (const inclusion of declaration.inclusions()) reportInclusion(inclusion, sources, diagnostics);
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
function reportInclusion(inclusion, sources, diagnostics) {
|
|
1257
|
-
if (inclusion.name() === void 0) return;
|
|
1258
|
-
diagnostics.push({
|
|
1259
|
-
code: "PSL_INVALID_DECLARATION",
|
|
1260
|
-
message: MIXINS_NOT_SUPPORTED,
|
|
1261
|
-
filename: sources.sourceFileFor(inclusion.syntax).filename,
|
|
1262
|
-
range: nodeRange(inclusion.syntax, sources)
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
function mixinKeywordRange(declaration, sources) {
|
|
1266
|
-
const token = declaration.mixinKeyword();
|
|
1267
|
-
if (token === void 0) return void 0;
|
|
1268
|
-
const sourceFile = sources.sourceFileFor(declaration.syntax);
|
|
1269
|
-
return {
|
|
1270
|
-
start: sourceFile.positionAt(token.offset),
|
|
1271
|
-
end: sourceFile.positionAt(token.offset + token.text.length)
|
|
1272
|
-
};
|
|
1273
|
-
}
|
|
1274
|
-
function buildFields(ownerName, fields, sources, diagnostics) {
|
|
1275
|
-
const result = Object.create(null);
|
|
1276
|
-
for (const field of fields) {
|
|
1277
|
-
const nameNode = field.name();
|
|
1278
|
-
const name = nameNode?.name();
|
|
1279
|
-
if (name === void 0) continue;
|
|
1280
|
-
if (Object.hasOwn(result, name)) {
|
|
1281
|
-
const range = nameRange(nameNode, sources);
|
|
1282
|
-
if (range) diagnostics.push({
|
|
1283
|
-
code: "PSL_DUPLICATE_DECLARATION",
|
|
1284
|
-
message: `Duplicate declaration of "${name}"`,
|
|
1285
|
-
filename: sources.sourceFileFor(field.syntax).filename,
|
|
1286
|
-
range
|
|
1287
|
-
});
|
|
1288
|
-
continue;
|
|
1289
|
-
}
|
|
1290
|
-
result[name] = buildField(ownerName, name, field, sources, diagnostics);
|
|
1291
|
-
}
|
|
1292
|
-
return result;
|
|
1293
|
-
}
|
|
1294
|
-
function buildField(ownerName, name, node, sources, diagnostics) {
|
|
1295
|
-
const attributes = readResolvedAttributes(node.attributes(), sources);
|
|
1296
|
-
const span = nodePslSpan(node.syntax, sources);
|
|
1297
|
-
const annotation = node.typeAnnotation();
|
|
1298
|
-
const typeName = annotation?.name();
|
|
1299
|
-
if (typeName?.isOverQualified()) {
|
|
1300
|
-
const path = typeName.path();
|
|
1301
|
-
diagnostics.push({
|
|
1302
|
-
code: "PSL_INVALID_QUALIFIED_TYPE",
|
|
1303
|
-
message: `Field "${ownerName}.${name}" has an invalid qualified type "${path.join(".")}"; use at most one namespace qualifier (e.g. "ns.TypeName")`,
|
|
1304
|
-
filename: sources.sourceFileFor(typeName.syntax).filename,
|
|
1305
|
-
range: nodeRange(typeName.syntax, sources)
|
|
1306
|
-
});
|
|
1307
|
-
return {
|
|
1308
|
-
kind: "field",
|
|
1309
|
-
name,
|
|
1310
|
-
node,
|
|
1311
|
-
span,
|
|
1312
|
-
typeName: path[path.length - 1] ?? "",
|
|
1313
|
-
optional: false,
|
|
1314
|
-
list: false,
|
|
1315
|
-
elementOptional: false,
|
|
1316
|
-
malformedType: true,
|
|
1317
|
-
attributes
|
|
1318
|
-
};
|
|
1319
|
-
}
|
|
1320
|
-
const typeConstructor = annotation?.isConstructor() ? readResolvedConstructorCall(annotation, sources) : void 0;
|
|
1321
|
-
const typeNamespaceId = typeName?.namespace()?.name();
|
|
1322
|
-
const typeContractSpaceId = typeName?.space()?.name();
|
|
1323
|
-
return {
|
|
1324
|
-
kind: "field",
|
|
1325
|
-
name,
|
|
1326
|
-
node,
|
|
1327
|
-
span,
|
|
1328
|
-
typeName: typeName?.identifier()?.name() ?? "",
|
|
1329
|
-
...typeNamespaceId !== void 0 ? { typeNamespaceId } : {},
|
|
1330
|
-
...typeContractSpaceId !== void 0 ? { typeContractSpaceId } : {},
|
|
1331
|
-
optional: annotation?.isOptional() ?? false,
|
|
1332
|
-
list: annotation?.isList() ?? false,
|
|
1333
|
-
elementOptional: annotation?.isElementOptional() ?? false,
|
|
1334
|
-
...typeConstructor !== void 0 ? { typeConstructor } : {},
|
|
1335
|
-
attributes
|
|
1336
|
-
};
|
|
1337
|
-
}
|
|
1338
|
-
function resolveNamedTypeBinding(node, sources) {
|
|
1339
|
-
const annotation = node.typeAnnotation();
|
|
1340
|
-
const isConstructor = annotation?.isConstructor() ?? false;
|
|
1341
|
-
const baseType = annotation?.name()?.identifier()?.name();
|
|
1342
|
-
const typeConstructor = readResolvedConstructorCall(annotation, sources);
|
|
1343
|
-
return {
|
|
1344
|
-
isConstructor,
|
|
1345
|
-
...!isConstructor && baseType !== void 0 ? { baseType } : {},
|
|
1346
|
-
...typeConstructor !== void 0 ? { typeConstructor } : {},
|
|
1347
|
-
attributes: readResolvedAttributes(node.attributes(), sources)
|
|
1348
|
-
};
|
|
1349
|
-
}
|
|
1350
|
-
function nameRange(name, sources) {
|
|
1351
|
-
if (name === void 0) return void 0;
|
|
1352
|
-
const sourceFile = sources.sourceFileFor(name.syntax);
|
|
1353
|
-
for (const token of name.syntax.tokens()) if (token.kind === "Ident") return {
|
|
1354
|
-
start: sourceFile.positionAt(token.offset),
|
|
1355
|
-
end: sourceFile.positionAt(token.offset + token.text.length)
|
|
1356
|
-
};
|
|
1357
|
-
}
|
|
1358
|
-
function nodeRange(node, sources) {
|
|
1359
|
-
const sourceFile = sources.sourceFileFor(node);
|
|
1360
|
-
const start = node.offset;
|
|
1361
|
-
const end = start + node.green.textLength;
|
|
1362
|
-
return {
|
|
1363
|
-
start: sourceFile.positionAt(start),
|
|
1364
|
-
end: sourceFile.positionAt(end)
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
1553
|
//#endregion
|
|
1368
1554
|
//#region ../../../1-framework/2-authoring/psl-parser/dist/index.mjs
|
|
1369
1555
|
function getPositionalArgument(attribute, index = 0) {
|