@xdbml/parse 0.3.2 → 0.5.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/dist/ast.d.ts +24 -8
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/keywords.d.ts +3 -3
- package/dist/keywords.js +14 -0
- package/dist/module-resolver.d.ts +3 -3
- package/dist/module-resolver.js +21 -11
- package/dist/name-resolver.d.ts +2 -2
- package/dist/name-resolver.js +43 -3
- package/dist/parser.d.ts +31 -7
- package/dist/parser.js +116 -18
- package/dist/relationships.d.ts +99 -0
- package/dist/relationships.js +436 -0
- package/dist/supertypes.d.ts +110 -0
- package/dist/supertypes.js +526 -0
- package/package.json +2 -1
package/dist/parser.js
CHANGED
|
@@ -13,11 +13,37 @@ import { TokenKind, tokenize, } from "./lexer.js";
|
|
|
13
13
|
import { resolveImport, classifyModuleSource, ModuleSourceError } from "./module-resolver.js";
|
|
14
14
|
export class ParseError extends Error {
|
|
15
15
|
position;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Optional machine-readable reason. Set for the errors a caller may want
|
|
18
|
+
* to tell apart from a plain syntax error: `unsupported-version` when a
|
|
19
|
+
* document declares a newer version than this parser supports (spec 4.1).
|
|
20
|
+
*/
|
|
21
|
+
code;
|
|
22
|
+
constructor(message, position, code) {
|
|
17
23
|
super(`${message} (line ${position.line}, column ${position.column})`);
|
|
18
24
|
this.position = position;
|
|
25
|
+
if (code)
|
|
26
|
+
this.code = code;
|
|
19
27
|
}
|
|
20
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* The newest specification version this parser implements. A document
|
|
31
|
+
* declaring a later version is refused (spec 4.1) rather than parsed with
|
|
32
|
+
* semantics it does not have.
|
|
33
|
+
*/
|
|
34
|
+
export const SUPPORTED_XDBML_VERSION = '0.5';
|
|
35
|
+
/** Compare dotted version strings numerically: -1, 0 or 1. */
|
|
36
|
+
export function compareVersions(a, b) {
|
|
37
|
+
const pa = a.split('.').map((n) => Number(n) || 0);
|
|
38
|
+
const pb = b.split('.').map((n) => Number(n) || 0);
|
|
39
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
40
|
+
const x = pa[i] ?? 0;
|
|
41
|
+
const y = pb[i] ?? 0;
|
|
42
|
+
if (x !== y)
|
|
43
|
+
return x < y ? -1 : 1;
|
|
44
|
+
}
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
21
47
|
/* -------------------------------------------------------------------------
|
|
22
48
|
* Keyword recognition.
|
|
23
49
|
*
|
|
@@ -31,13 +57,13 @@ const CONTAINER_KEYWORDS = new Set([
|
|
|
31
57
|
const ENTITY_KEYWORDS = new Set(['table', 'entity', 'collection', 'record']);
|
|
32
58
|
/**
|
|
33
59
|
* Element-type keywords accepted in module-system import items
|
|
34
|
-
* (spec §
|
|
60
|
+
* (spec §27.3). Stored lowercased; matching is case-insensitive.
|
|
35
61
|
*
|
|
36
62
|
* `field` is recognized but explicitly rejected by parseImportItem in P4
|
|
37
63
|
* (field-level imports have special declaration-vs-placement semantics
|
|
38
64
|
* that will land in a later batch).
|
|
39
65
|
*
|
|
40
|
-
* `project` is intentionally excluded -- spec §
|
|
66
|
+
* `project` is intentionally excluded -- spec §27.1 forbids importing
|
|
41
67
|
* Project declarations.
|
|
42
68
|
*/
|
|
43
69
|
const IMPORT_ELEMENT_TYPES = new Set([
|
|
@@ -45,7 +71,7 @@ const IMPORT_ELEMENT_TYPES = new Set([
|
|
|
45
71
|
'enum', 'tablepartial', 'note',
|
|
46
72
|
'schema', 'container', 'tablegroup',
|
|
47
73
|
'type', 'edge', 'view', 'diagramview',
|
|
48
|
-
'field',
|
|
74
|
+
'field', 'supertypegroup',
|
|
49
75
|
]);
|
|
50
76
|
const STRUCTURAL_TYPE_KEYWORDS = new Set([
|
|
51
77
|
'object', 'struct', 'record', 'array', 'list', 'map', 'dict', 'dictionary',
|
|
@@ -98,7 +124,7 @@ export class Parser {
|
|
|
98
124
|
* The set of file paths currently being parsed in the resolution chain.
|
|
99
125
|
* Used for cycle detection: when resolving a directive whose `from` path
|
|
100
126
|
* is already in this set, the parser produces an empty clone for that
|
|
101
|
-
* directive rather than recursing (matching spec §
|
|
127
|
+
* directive rather than recursing (matching spec §27.15: cycles are
|
|
102
128
|
* allowed; name resolution handles them). The set is passed by reference
|
|
103
129
|
* across recursive parse() calls so all transitive levels see it.
|
|
104
130
|
*
|
|
@@ -179,6 +205,11 @@ export class Parser {
|
|
|
179
205
|
this.advance(); // xdbml
|
|
180
206
|
this.expect(TokenKind.Colon, "Expected ':' after 'xdbml'");
|
|
181
207
|
const numTok = this.expect(TokenKind.NumberLiteral, 'Expected version number');
|
|
208
|
+
if (compareVersions(numTok.text, SUPPORTED_XDBML_VERSION) > 0) {
|
|
209
|
+
throw new ParseError(`This document declares 'xdbml: ${numTok.text}', which is newer than the ` +
|
|
210
|
+
`latest version this parser supports (${SUPPORTED_XDBML_VERSION}). ` +
|
|
211
|
+
'Use a newer parser, or declare a supported version.', numTok.start, 'unsupported-version');
|
|
212
|
+
}
|
|
182
213
|
return {
|
|
183
214
|
kind: 'VersionDeclaration',
|
|
184
215
|
version: numTok.text,
|
|
@@ -231,6 +262,8 @@ export class Parser {
|
|
|
231
262
|
return this.parseTablePartial();
|
|
232
263
|
if (k === 'tablegroup')
|
|
233
264
|
return this.parseTableGroup();
|
|
265
|
+
if (k === 'supertypegroup')
|
|
266
|
+
return this.parseSupertypeGroup();
|
|
234
267
|
if (k === 'note')
|
|
235
268
|
return this.parseNoteDeclaration();
|
|
236
269
|
if (k === 'records')
|
|
@@ -477,7 +510,7 @@ export class Parser {
|
|
|
477
510
|
};
|
|
478
511
|
}
|
|
479
512
|
/**
|
|
480
|
-
* Parse a `records { ... }` block inside an entity body (§
|
|
513
|
+
* Parse a `records { ... }` block inside an entity body (§26.1, implicit
|
|
481
514
|
* column list). Values are stored as SettingValue cells; row boundaries
|
|
482
515
|
* are determined by source line (see `parseRecordRow`).
|
|
483
516
|
*/
|
|
@@ -497,7 +530,7 @@ export class Parser {
|
|
|
497
530
|
};
|
|
498
531
|
}
|
|
499
532
|
/**
|
|
500
|
-
* Top-level records declaration (§
|
|
533
|
+
* Top-level records declaration (§26.2, new in v0.2):
|
|
501
534
|
*
|
|
502
535
|
* records users (id, name, email) { ... }
|
|
503
536
|
* records core.users (id, name, email) { ... }
|
|
@@ -587,7 +620,7 @@ export class Parser {
|
|
|
587
620
|
span: this.spanFrom(start),
|
|
588
621
|
};
|
|
589
622
|
}
|
|
590
|
-
/* ----- Module-system directives (spec §
|
|
623
|
+
/* ----- Module-system directives (spec §27, new in v0.2) ----- */
|
|
591
624
|
/**
|
|
592
625
|
* Parse a `use` or `reuse` directive. Called from both the top-level
|
|
593
626
|
* dispatcher and the Container body dispatcher; the caller indicates
|
|
@@ -701,7 +734,7 @@ export class Parser {
|
|
|
701
734
|
resolvedPath = result.resolvedPath;
|
|
702
735
|
break;
|
|
703
736
|
case 'cycle':
|
|
704
|
-
// Per spec §
|
|
737
|
+
// Per spec §27.15, cycles are allowed; the parser produces a
|
|
705
738
|
// directive with no clone, and name resolution (P6+) is
|
|
706
739
|
// expected to bridge the cycle. We leave clone undefined.
|
|
707
740
|
resolvedPath = result.resolvedPath;
|
|
@@ -759,12 +792,12 @@ export class Parser {
|
|
|
759
792
|
`Expected one of: ${Array.from(IMPORT_ELEMENT_TYPES).join(', ')}.`, elemTok.start);
|
|
760
793
|
}
|
|
761
794
|
if (elementType === 'field' && context !== 'file-scope') {
|
|
762
|
-
// Spec §
|
|
795
|
+
// Spec §27.8: field imports must appear at file scope. Inside a
|
|
763
796
|
// Container body, the field's eventual placement (as a Named Type)
|
|
764
797
|
// would have no meaningful container scope -- field imports are
|
|
765
798
|
// always lifted to file scope by flatten(), regardless of where
|
|
766
799
|
// the directive sits.
|
|
767
|
-
throw new ParseError(`Field-level imports must appear at file scope, not inside a Container body (spec §
|
|
800
|
+
throw new ParseError(`Field-level imports must appear at file scope, not inside a Container body (spec §27.8).`, elemTok.start);
|
|
768
801
|
}
|
|
769
802
|
this.advance(); // consume element type keyword
|
|
770
803
|
// Dotted source path.
|
|
@@ -795,12 +828,12 @@ export class Parser {
|
|
|
795
828
|
* that match the import items by name and element type (matching is
|
|
796
829
|
* downstream-consumer's job; the parser is permissive).
|
|
797
830
|
*
|
|
798
|
-
* Per spec §
|
|
831
|
+
* Per spec §27.6, clone content uses the importing file's vocabulary
|
|
799
832
|
* (aliases already applied) and is parsed under the importing file's
|
|
800
833
|
* xdbml version directive.
|
|
801
834
|
*
|
|
802
835
|
* Most clone-block content uses TopLevelStatement shapes (Entity, Type,
|
|
803
|
-
* Container, etc.). The exception is field imports (§
|
|
836
|
+
* Container, etc.). The exception is field imports (§27.8): when the
|
|
804
837
|
* directive imports one or more fields via `field <path>` items, the
|
|
805
838
|
* clone block holds each field as a bare FieldDeclaration with no entity
|
|
806
839
|
* wrapper. The dispatch below checks whether the next token starts a
|
|
@@ -816,7 +849,7 @@ export class Parser {
|
|
|
816
849
|
statements.push(this.parseTopLevelStatement());
|
|
817
850
|
}
|
|
818
851
|
else {
|
|
819
|
-
// Bare field declaration -- the field-import case. Per spec §
|
|
852
|
+
// Bare field declaration -- the field-import case. Per spec §27.6
|
|
820
853
|
// the field appears without an entity wrapper.
|
|
821
854
|
statements.push(this.parseFieldDeclaration());
|
|
822
855
|
}
|
|
@@ -1284,7 +1317,7 @@ export class Parser {
|
|
|
1284
1317
|
}
|
|
1285
1318
|
throw new ParseError(`Expected type parameter, got ${t.kind}`, t.start);
|
|
1286
1319
|
}
|
|
1287
|
-
/* ----- Type declaration (§
|
|
1320
|
+
/* ----- Type declaration (§15) ----- */
|
|
1288
1321
|
parseTypeDecl() {
|
|
1289
1322
|
const start = this.peek().start;
|
|
1290
1323
|
this.advance(); // Type
|
|
@@ -1293,7 +1326,7 @@ export class Parser {
|
|
|
1293
1326
|
//
|
|
1294
1327
|
// { ... } v0.1 object form, no pre-body settings
|
|
1295
1328
|
// [ settings ] { ... } v0.1 object form, pre-body settings (permissive)
|
|
1296
|
-
// typeExpression v0.2 scalar form (spec §
|
|
1329
|
+
// typeExpression v0.2 scalar form (spec §15.7)
|
|
1297
1330
|
// typeExpression [ settings ] v0.2 scalar form with field-level settings
|
|
1298
1331
|
//
|
|
1299
1332
|
// Note that LBrace and LBracket are distinct from any start-of-type-expression
|
|
@@ -1494,8 +1527,12 @@ export class Parser {
|
|
|
1494
1527
|
settings = this.maybeSettingsBlock();
|
|
1495
1528
|
}
|
|
1496
1529
|
else if (this.match(TokenKind.LBrace)) {
|
|
1497
|
-
// long form: `Ref name { a > b }
|
|
1530
|
+
// long form: `Ref name { a > b }`, or, since v0.4, with a settings
|
|
1531
|
+
// block after the relationship expression: `Ref name { a > b [flag] }`.
|
|
1532
|
+
// Accepting settings here puts every setting of spec 11.9 in all three
|
|
1533
|
+
// declaration forms; a long form written without one parses as before.
|
|
1498
1534
|
spec = this.parseRefSpec();
|
|
1535
|
+
settings = this.maybeSettingsBlock();
|
|
1499
1536
|
this.expect(TokenKind.RBrace, "Expected '}' closing Ref body");
|
|
1500
1537
|
}
|
|
1501
1538
|
else {
|
|
@@ -1568,7 +1605,7 @@ export class Parser {
|
|
|
1568
1605
|
};
|
|
1569
1606
|
}
|
|
1570
1607
|
/**
|
|
1571
|
-
* Parse a dotted path with the §
|
|
1608
|
+
* Parse a dotted path with the §20 segment vocabulary:
|
|
1572
1609
|
*
|
|
1573
1610
|
* IDENTIFIER -- a field segment
|
|
1574
1611
|
* .IDENTIFIER -- field
|
|
@@ -1742,6 +1779,67 @@ export class Parser {
|
|
|
1742
1779
|
span: this.spanFrom(start),
|
|
1743
1780
|
};
|
|
1744
1781
|
}
|
|
1782
|
+
/* ----- SupertypeGroup (spec §12, new in v0.5) ----- */
|
|
1783
|
+
/**
|
|
1784
|
+
* `SupertypeGroup <name> [supertype: X, ...] { Sub1 Sub2 [strategy: y] }`.
|
|
1785
|
+
* Members are separated like TableGroup members: newline, comma or
|
|
1786
|
+
* semicolon (spec §3.9). A name is required (§12.1); a writer exporting a
|
|
1787
|
+
* group that has none emits `undefinedGroup1`, `undefinedGroup2`, ... so
|
|
1788
|
+
* the parser never supplies one. Values are validated after parsing, by
|
|
1789
|
+
* `checkSupertypeGroups()`, so an unknown value gets a located diagnostic
|
|
1790
|
+
* rather than stopping the parse.
|
|
1791
|
+
*/
|
|
1792
|
+
parseSupertypeGroup() {
|
|
1793
|
+
const start = this.peek().start;
|
|
1794
|
+
this.advance(); // SupertypeGroup
|
|
1795
|
+
const nameTok = this.peek();
|
|
1796
|
+
if (nameTok.kind !== TokenKind.Identifier && nameTok.kind !== TokenKind.QuotedIdentifier) {
|
|
1797
|
+
throw new ParseError('Expected a name after SupertypeGroup. Every group has a name (spec §12.1); ' +
|
|
1798
|
+
'a group exported without one is written undefinedGroup1, undefinedGroup2, ...', nameTok.start);
|
|
1799
|
+
}
|
|
1800
|
+
const name = this.parseIdentLikeName('SupertypeGroup name');
|
|
1801
|
+
const settings = this.maybeSettingsBlock();
|
|
1802
|
+
this.expect(TokenKind.LBrace, "Expected '{' after SupertypeGroup name and settings");
|
|
1803
|
+
const members = [];
|
|
1804
|
+
while (!this.check(TokenKind.RBrace) && !this.check(TokenKind.EOF)) {
|
|
1805
|
+
const t = this.peek();
|
|
1806
|
+
if (t.kind === TokenKind.Identifier || t.kind === TokenKind.QuotedIdentifier) {
|
|
1807
|
+
const memberStart = t.start;
|
|
1808
|
+
this.advance();
|
|
1809
|
+
let n = t.kind === TokenKind.QuotedIdentifier ? (t.value ?? '') : t.text;
|
|
1810
|
+
while (this.check(TokenKind.Dot)) {
|
|
1811
|
+
this.advance();
|
|
1812
|
+
const next = this.peek();
|
|
1813
|
+
if (next.kind !== TokenKind.Identifier && next.kind !== TokenKind.QuotedIdentifier) {
|
|
1814
|
+
throw new ParseError('Expected identifier after dot in subtype path', next.start);
|
|
1815
|
+
}
|
|
1816
|
+
this.advance();
|
|
1817
|
+
n += `.${next.kind === TokenKind.QuotedIdentifier ? (next.value ?? '') : next.text}`;
|
|
1818
|
+
}
|
|
1819
|
+
const memberSettings = this.maybeSettingsBlock();
|
|
1820
|
+
members.push({
|
|
1821
|
+
kind: 'SupertypeGroupMember',
|
|
1822
|
+
name: n,
|
|
1823
|
+
settings: memberSettings,
|
|
1824
|
+
span: this.spanFrom(memberStart),
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
else if (t.kind === TokenKind.Semicolon || t.kind === TokenKind.Comma) {
|
|
1828
|
+
this.advance();
|
|
1829
|
+
}
|
|
1830
|
+
else {
|
|
1831
|
+
throw new ParseError(`Unexpected ${t.kind} in SupertypeGroup body; expected a subtype entity name`, t.start);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
this.expect(TokenKind.RBrace, "Expected '}' closing SupertypeGroup");
|
|
1835
|
+
return {
|
|
1836
|
+
kind: 'SupertypeGroupDeclaration',
|
|
1837
|
+
name,
|
|
1838
|
+
settings,
|
|
1839
|
+
members,
|
|
1840
|
+
span: this.spanFrom(start),
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1745
1843
|
/* ----- Indexes ----- */
|
|
1746
1844
|
parseIndexes() {
|
|
1747
1845
|
const start = this.peek().start;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relationship helpers and checks (spec 11.10 through 11.12, new in v0.4).
|
|
3
|
+
*
|
|
4
|
+
* A `Ref` carries its relationship type in its settings block. The
|
|
5
|
+
* `foreign_master` flag marks denormalized replication: the parent endpoint
|
|
6
|
+
* holds the master value for a copy held at the child endpoint. Absence of
|
|
7
|
+
* the flag marks a referential relationship, the foreign key.
|
|
8
|
+
*
|
|
9
|
+
* This module holds three things:
|
|
10
|
+
*
|
|
11
|
+
* 1. `relationshipType()` and `isForeignMaster()` -- one definition of the
|
|
12
|
+
* type test, so the renderer, the MCP server, and any generator agree
|
|
13
|
+
* rather than each re-reading the settings array.
|
|
14
|
+
*
|
|
15
|
+
* 2. `refChildEndpoint()` / `refParentEndpoint()` -- which side of a Ref is
|
|
16
|
+
* the child. The cardinality operator decides: `>` and `-` put the child
|
|
17
|
+
* on the left, `<` puts it on the right. `<>` has no single child.
|
|
18
|
+
*
|
|
19
|
+
* 3. `checkRelationships()` -- the semantic rules of spec 11.11 that the
|
|
20
|
+
* grammar cannot express. Called from `resolveNames()`, so every
|
|
21
|
+
* consumer of the resolver's diagnostics gets them without opting in.
|
|
22
|
+
*/
|
|
23
|
+
import type { Diagnostic } from './name-resolver.ts';
|
|
24
|
+
import type { PathSegment, RefDeclaration, RefEndpoint, RefValue, Setting, XDbmlDocument } from './ast.ts';
|
|
25
|
+
export type RelationshipType = 'referential' | 'foreign_master';
|
|
26
|
+
/** The flag name, spelled once. */
|
|
27
|
+
export declare const FOREIGN_MASTER_FLAG = "foreign_master";
|
|
28
|
+
/** Accepted values of the `constraint_type` setting (spec 11.15). */
|
|
29
|
+
export declare const CONSTRAINT_TYPES: readonly ["identifying", "non_identifying"];
|
|
30
|
+
export type ConstraintType = (typeof CONSTRAINT_TYPES)[number];
|
|
31
|
+
/**
|
|
32
|
+
* Relationship settings introduced in v0.4 alongside the foreign master
|
|
33
|
+
* flag. Gated on the declared version like the flag itself, so a document
|
|
34
|
+
* declaring an earlier version does not quietly carry v0.4 semantics.
|
|
35
|
+
*/
|
|
36
|
+
export declare const V04_RELATIONSHIP_SETTINGS: readonly ["source_role", "target_role", "source_verb", "target_verb", "constraint_type"];
|
|
37
|
+
/** The `constraint_type` a Ref declares, or undefined when unstated. */
|
|
38
|
+
export declare function constraintType(ref: RefDeclaration): ConstraintType | undefined;
|
|
39
|
+
/** True when the Ref is marked `undirected: true` (spec 11.16.2). */
|
|
40
|
+
export declare function isUndirected(ref: RefDeclaration): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* True when a settings array carries the `foreign_master` flag. The flag
|
|
43
|
+
* takes no value, so presence is the whole test; a `foreign_master: true`
|
|
44
|
+
* spelling is accepted as well rather than silently ignored, since a user
|
|
45
|
+
* reaching for the more explicit form means the same thing.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hasForeignMasterFlag(settings: ReadonlyArray<Setting>): boolean;
|
|
48
|
+
/** The relationship type a Ref declares. */
|
|
49
|
+
export declare function relationshipType(ref: RefDeclaration): RelationshipType;
|
|
50
|
+
/** Convenience wrapper over `relationshipType`. */
|
|
51
|
+
export declare function isForeignMaster(ref: RefDeclaration): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The child endpoint of a Ref, i.e. the side holding the copy (for a foreign
|
|
54
|
+
* master) or the foreign key (for a referential relationship).
|
|
55
|
+
*
|
|
56
|
+
* a.x > b.y many a to one b -> a.x is the child
|
|
57
|
+
* a.x < b.y one a to many b -> b.y is the child
|
|
58
|
+
* a.x - b.y one to one -> a.x is the child, by convention
|
|
59
|
+
* a.x <> b.y many to many -> no single child; returns undefined
|
|
60
|
+
*/
|
|
61
|
+
export declare function refChildEndpoint(ref: RefDeclaration): RefEndpoint | undefined;
|
|
62
|
+
/** The parent endpoint of a Ref, i.e. the opposite side of the child. */
|
|
63
|
+
export declare function refParentEndpoint(ref: RefDeclaration): RefEndpoint | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Every name an entity answers to in a document: its own name, and its
|
|
66
|
+
* container-qualified name where it sits inside one. Mirrors the index the
|
|
67
|
+
* renderer builds, so both agree on what an entity-level path looks like.
|
|
68
|
+
*/
|
|
69
|
+
export declare function entityNames(doc: XDbmlDocument): Set<string>;
|
|
70
|
+
/**
|
|
71
|
+
* True when an endpoint names an entity and stops there (spec 11.16), as in
|
|
72
|
+
* `Customer` or `shop.orders`. A structural test is not enough: `b.aid` has
|
|
73
|
+
* the same shape and names a field, so the whole path is checked against the
|
|
74
|
+
* entities the document declares.
|
|
75
|
+
*/
|
|
76
|
+
export declare function isEntityLevelEndpoint(endpoint: RefEndpoint, names: Set<string>): boolean;
|
|
77
|
+
/** Render a path as a dotted string, for messages and for identity keys. */
|
|
78
|
+
export declare function pathToString(path: ReadonlyArray<PathSegment>): string;
|
|
79
|
+
/**
|
|
80
|
+
* True when the document declares at least `min`. A document with no version
|
|
81
|
+
* declaration is plain DBML and supports no xDBML construct, so it fails
|
|
82
|
+
* every gate.
|
|
83
|
+
*
|
|
84
|
+
* Kept general rather than special-cased to the foreign master flag: the
|
|
85
|
+
* module-system gates described in the grammar notes are not implemented yet
|
|
86
|
+
* and can adopt this helper when they are.
|
|
87
|
+
*/
|
|
88
|
+
export declare function versionAtLeast(doc: XDbmlDocument, min: string): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Semantic checks for foreign master relationships (spec 11.11), plus the
|
|
91
|
+
* inline-form rule of 11.10.2 and the version gate of section 4.
|
|
92
|
+
*
|
|
93
|
+
* The composite rule is checked here rather than in the grammar so the error
|
|
94
|
+
* can name the flag that makes the composite invalid, instead of failing on
|
|
95
|
+
* a form that is perfectly legal for a referential relationship.
|
|
96
|
+
*/
|
|
97
|
+
export declare function checkRelationships(doc: XDbmlDocument): Diagnostic[];
|
|
98
|
+
/** Re-exported for consumers that only need the inline ref value shape. */
|
|
99
|
+
export type { RefValue };
|