@syncular/typegen 0.6.0 → 0.7.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/query.js CHANGED
@@ -84,6 +84,8 @@ const DECLTYPE_MAP = {
84
84
  BLOBREF: 'blob_ref',
85
85
  CRDT: 'crdt',
86
86
  };
87
+ /** Local client protocol column; query-only and never part of schema IR. */
88
+ const SYNC_VERSION_COLUMN = '_sync_version';
87
89
  const DEFAULT_NAMING = { naming: 'camel', targets: ['ts'] };
88
90
  // -- path → name --------------------------------------------------------------
89
91
  /** A single kebab-case path segment (folder) or filename stem. */
@@ -533,6 +535,17 @@ function resolveSource(item, refs, ir) {
533
535
  }
534
536
  return null;
535
537
  }
538
+ /** Resolve the one supported query-only protocol column. SQLite still proves
539
+ * qualifier/ambiguity against the synthesized local tables. */
540
+ function isSyncVersionSource(item, refs) {
541
+ const match = PLAIN_REF_RE.exec(item.expr);
542
+ if (match === null || match[2] !== SYNC_VERSION_COLUMN)
543
+ return false;
544
+ const qualifier = match[1];
545
+ return qualifier === undefined
546
+ ? refs.length === 1
547
+ : refs.some((ref) => ref.alias === qualifier);
548
+ }
536
549
  // -- param type inference -----------------------------------------------------
537
550
  //
538
551
  // Infer a param's type from `col <op> :name` or `col IN (:name, …)` where `col`
@@ -797,6 +810,10 @@ export function synthesizeDdl(ir) {
797
810
  const pk = c.name === table.primaryKey ? ' PRIMARY KEY' : '';
798
811
  return ` ${c.name} ${SQL_TYPE[c.type]}${pk}${notNull}`;
799
812
  });
813
+ // The materialized local client table always carries this hidden protocol
814
+ // token. It is absent from IR mutation types but may be explicitly aliased
815
+ // by a named read query for optimistic concurrency.
816
+ cols.push(` ${SYNC_VERSION_COLUMN} INTEGER NOT NULL DEFAULT -1`);
800
817
  lines.push(`CREATE TABLE ${table.name} (\n${cols.join(',\n')}\n);`);
801
818
  // Create the declared indexes too — harmless for prepare()/decltype, and
802
819
  // keeps the type-check DB's shape honest with what the client materializes.
@@ -881,6 +898,18 @@ export function analyzeStatement(name, location, statementText, ir, db, naming =
881
898
  const source = item !== undefined ? resolveSource(item, refs, ir) : null;
882
899
  const sqlName = sqlNames[index] ?? colName;
883
900
  const langName = langNames[index] ?? colName;
901
+ if (item !== undefined && isSyncVersionSource(item, refs)) {
902
+ if (sqlName === SYNC_VERSION_COLUMN) {
903
+ throw new TypegenError(file, `${SYNC_VERSION_COLUMN} is stripped from app-facing query rows unless explicitly aliased (for example \`${SYNC_VERSION_COLUMN} AS server_version\`)`);
904
+ }
905
+ return {
906
+ name: sqlName,
907
+ langName,
908
+ type: 'integer',
909
+ nullable: false,
910
+ fidelity: 'exact',
911
+ };
912
+ }
884
913
  if (source !== null) {
885
914
  // Exact: IR column type + IR nullability. (decltype agrees; we prefer
886
915
  // the IR type so blob_ref/crdt/json semantic types survive.)
@@ -19,15 +19,8 @@ export type SyqlSemanticTemplateNode = {
19
19
  } | {
20
20
  readonly kind: 'when';
21
21
  readonly controls: readonly string[];
22
+ readonly explicitPresence: readonly boolean[];
22
23
  readonly body: readonly SyqlSemanticTemplateNode[];
23
- } | {
24
- readonly kind: 'scope' | 'cover';
25
- readonly bindings: readonly {
26
- readonly qualifier: string;
27
- readonly column: string;
28
- readonly operator: 'equal' | 'in';
29
- readonly values: readonly string[];
30
- }[];
31
24
  };
32
25
  export interface SyqlSemanticTemplate {
33
26
  readonly mode: SyqlTemplate['tree']['mode'];
@@ -38,10 +31,12 @@ export type SyqlSemanticQueryParameter = {
38
31
  readonly name: string;
39
32
  readonly optional: boolean;
40
33
  readonly type?: SyqlSemanticType;
34
+ readonly default?: false;
41
35
  } | {
42
- readonly kind: 'switch';
36
+ readonly kind: 'range';
43
37
  readonly name: string;
44
- readonly optional: true;
38
+ readonly optional: boolean;
39
+ readonly type?: SyqlSemanticType;
45
40
  } | {
46
41
  readonly kind: 'group';
47
42
  readonly name: string;
@@ -62,8 +57,13 @@ export type SyqlSemanticDeclaration = {
62
57
  } | {
63
58
  readonly kind: 'query';
64
59
  readonly name: string;
60
+ readonly sync: boolean;
61
+ readonly syncBy?: {
62
+ readonly qualifier: string;
63
+ readonly column: string;
64
+ };
65
65
  readonly parameters: readonly SyqlSemanticQueryParameter[];
66
- readonly sql: SyqlSemanticTemplate;
66
+ readonly statement: SyqlSemanticTemplate;
67
67
  readonly sort?: {
68
68
  readonly control: string;
69
69
  readonly defaultProfile: string;
@@ -72,12 +72,11 @@ export type SyqlSemanticDeclaration = {
72
72
  readonly order: SyqlSemanticTemplate;
73
73
  }[];
74
74
  };
75
- readonly page?: {
75
+ readonly limit?: {
76
76
  readonly control: string;
77
77
  readonly defaultSize: number;
78
78
  readonly maxSize: number;
79
79
  };
80
- readonly identity?: readonly string[];
81
80
  };
82
81
  export interface SyqlSemanticFile {
83
82
  readonly kind: 'syql-file';
package/dist/syql-ast.js CHANGED
@@ -10,8 +10,14 @@ function semanticMember(member) {
10
10
  return { name: member.name, ...(type === undefined ? {} : { type }) };
11
11
  }
12
12
  function semanticParameter(parameter) {
13
- if (parameter.kind === 'switch') {
14
- return { kind: 'switch', name: parameter.name, optional: true };
13
+ if (parameter.kind === 'range') {
14
+ const type = semanticType(parameter.type);
15
+ return {
16
+ kind: 'range',
17
+ name: parameter.name,
18
+ optional: parameter.optional,
19
+ ...(type === undefined ? {} : { type }),
20
+ };
15
21
  }
16
22
  if (parameter.kind === 'group') {
17
23
  return {
@@ -27,6 +33,7 @@ function semanticParameter(parameter) {
27
33
  name: parameter.name,
28
34
  optional: parameter.optional,
29
35
  ...(type === undefined ? {} : { type }),
36
+ ...(parameter.default === undefined ? {} : { default: parameter.default }),
30
37
  };
31
38
  }
32
39
  function semanticRawTokens(tokens) {
@@ -50,18 +57,11 @@ function semanticNode(node) {
50
57
  return {
51
58
  kind: 'when',
52
59
  controls: node.controls,
60
+ explicitPresence: node.explicitPresence,
53
61
  body: semanticNodes(node.body.nodes),
54
62
  };
55
63
  }
56
- return {
57
- kind: node.kind,
58
- bindings: node.bindings.map((binding) => ({
59
- qualifier: binding.column.qualifier,
60
- column: binding.column.name,
61
- operator: binding.operator,
62
- values: binding.values.map((value) => value.name),
63
- })),
64
- };
64
+ return undefined;
65
65
  }
66
66
  function semanticNodes(nodes) {
67
67
  return nodes.flatMap((node) => {
@@ -93,8 +93,17 @@ function semanticDeclaration(declaration) {
93
93
  return {
94
94
  kind: 'query',
95
95
  name: declaration.name,
96
+ sync: declaration.sync,
97
+ ...(declaration.syncBy === undefined
98
+ ? {}
99
+ : {
100
+ syncBy: {
101
+ qualifier: declaration.syncBy.qualifier,
102
+ column: declaration.syncBy.column,
103
+ },
104
+ }),
96
105
  parameters: declaration.parameters.map(semanticParameter),
97
- sql: semanticTemplate(declaration.sql.body),
106
+ statement: semanticTemplate(declaration.statement),
98
107
  ...(declaration.sort === undefined
99
108
  ? {}
100
109
  : {
@@ -107,18 +116,15 @@ function semanticDeclaration(declaration) {
107
116
  })),
108
117
  },
109
118
  }),
110
- ...(declaration.page === undefined
119
+ ...(declaration.limit === undefined
111
120
  ? {}
112
121
  : {
113
- page: {
114
- control: declaration.page.control,
115
- defaultSize: declaration.page.defaultSize,
116
- maxSize: declaration.page.maxSize,
122
+ limit: {
123
+ control: declaration.limit.control,
124
+ defaultSize: declaration.limit.defaultSize,
125
+ maxSize: declaration.limit.maxSize,
117
126
  },
118
127
  }),
119
- ...(declaration.identity === undefined
120
- ? {}
121
- : { identity: declaration.identity.fields }),
122
128
  };
123
129
  }
124
130
  /** Return the stable syntax/semantic AST pinned by `spec/syql` fixtures. */
@@ -3,26 +3,17 @@ import { TypegenError } from './errors.js';
3
3
  import { buildNamingMap } from './naming.js';
4
4
  import { analyzeStatement, } from './query.js';
5
5
  import { lexSyqlSqlSource } from './syql-lexer.js';
6
+ import { syqlRangeEndBind, syqlRangeStartBind } from './syql-semantics.js';
6
7
  const DEFAULT_NAMING = {
7
8
  naming: 'camel',
8
9
  targets: ['ts'],
9
10
  backend: 'auto',
10
11
  };
11
12
  const DEFAULT_ENUMERATION_LIMIT = 256;
12
- const PAGE_BIND = '__syqlPageSize';
13
+ const LIMIT_BIND = '__syqlLimit';
13
14
  function fail(code, query, message) {
14
15
  throw new TypegenError(`${query.module.file} (query ${query.declaration.name})`, `${code}: ${message}`);
15
16
  }
16
- function renderDirective(node) {
17
- const predicates = node.directive.bindings.map((binding) => {
18
- const column = `${binding.column.qualifier}.${binding.column.name}`;
19
- const values = binding.values.map((value) => `:${value.name}`);
20
- return binding.operator === 'equal'
21
- ? `${column} = ${values[0]}`
22
- : `${column} in (${values.join(', ')})`;
23
- });
24
- return `(${predicates.join(' and ')})`;
25
- }
26
17
  function renderTemplate(nodes, conditions, mode) {
27
18
  return nodes
28
19
  .map((node) => {
@@ -34,9 +25,6 @@ function renderTemplate(nodes, conditions, mode) {
34
25
  if (node.kind === 'predicate') {
35
26
  return `(${renderTemplate(node.body, conditions, mode)})`;
36
27
  }
37
- if (node.kind === 'scope' || node.kind === 'cover') {
38
- return renderDirective(node);
39
- }
40
28
  if (node.kind !== 'when') {
41
29
  throw new Error('revision-1 lowering found an unknown logical node');
42
30
  }
@@ -75,7 +63,7 @@ function outerLimitOffset(sql, file) {
75
63
  }
76
64
  return sql.length;
77
65
  }
78
- function composeControls(sql, file, sortSql, page) {
66
+ function composeControls(sql, file, sortSql, limit) {
79
67
  let out = sql.trim();
80
68
  if (sortSql !== undefined) {
81
69
  const insertion = outerLimitOffset(out, file);
@@ -83,10 +71,10 @@ function composeControls(sql, file, sortSql, page) {
83
71
  .slice(insertion)
84
72
  .trimStart()}`.trim();
85
73
  }
86
- if (page !== undefined) {
74
+ if (limit !== undefined) {
87
75
  // `coalesce` gives the generator's metadata-only execution a valid value;
88
76
  // runtimes still validate and bind the effective size before execution.
89
- out = `${out.trimEnd()} limit min(coalesce(:${PAGE_BIND}, ${page.defaultSize}), ${page.maxSize})`;
77
+ out = `${out.trimEnd()} limit min(coalesce(:${LIMIT_BIND}, ${limit.defaultSize}), ${limit.maxSize})`;
90
78
  }
91
79
  return out;
92
80
  }
@@ -101,7 +89,7 @@ function distinctBindNames(sql, file) {
101
89
  }
102
90
  return names;
103
91
  }
104
- function headersFor(names, valueOwners, conditionBinds, page, query) {
92
+ function headersFor(names, valueOwners, conditionBinds, limit, query) {
105
93
  return names
106
94
  .map((name) => {
107
95
  const value = valueOwners.get(name);
@@ -109,13 +97,13 @@ function headersFor(names, valueOwners, conditionBinds, page, query) {
109
97
  return `-- param :${name} ${value.type}`;
110
98
  if (conditionBinds.has(name))
111
99
  return `-- param :${name} boolean`;
112
- if (name === PAGE_BIND && page !== undefined)
100
+ if (name === LIMIT_BIND && limit !== undefined)
113
101
  return `-- param :${name} integer`;
114
102
  return fail('SYQL7002_INTERNAL_LOWERING', query, `generated SQL contains unresolved bind :${name}`);
115
103
  })
116
104
  .join('\n');
117
105
  }
118
- function planBind(name, valueOwners, conditionBinds, conditions, page, query) {
106
+ function planBind(name, valueOwners, conditionBinds, conditions, limit, query) {
119
107
  const value = valueOwners.get(name);
120
108
  if (value?.kind === 'value') {
121
109
  return { kind: 'value', name, type: value.type, input: value.input };
@@ -139,12 +127,12 @@ function planBind(name, valueOwners, conditionBinds, conditions, page, query) {
139
127
  controls: conditions[condition].controls,
140
128
  };
141
129
  }
142
- if (name === PAGE_BIND && page !== undefined) {
130
+ if (name === LIMIT_BIND && limit !== undefined) {
143
131
  return {
144
- kind: 'page',
132
+ kind: 'limit',
145
133
  name,
146
134
  type: 'integer',
147
- input: page.control,
135
+ input: limit.control,
148
136
  };
149
137
  }
150
138
  return fail('SYQL7002_INTERNAL_LOWERING', query, `cannot describe generated bind :${name}`);
@@ -155,17 +143,34 @@ function publicInputs(validated, naming) {
155
143
  const publicNames = [
156
144
  ...declaration.parameters.map((parameter) => parameter.name),
157
145
  ...(declaration.sort === undefined ? [] : [declaration.sort.control]),
158
- ...(declaration.page === undefined ? [] : [declaration.page.control]),
146
+ ...(declaration.limit === undefined ? [] : [declaration.limit.control]),
159
147
  ];
160
148
  const mapped = new Map(buildNamingMap(publicNames, naming.naming, query.module.file, `query ${declaration.name} public inputs`, naming.targets).map((entry) => [entry.sqlName, entry.langName]));
161
149
  const result = declaration.parameters.map((parameter) => {
162
150
  const langName = mapped.get(parameter.name);
163
- if (parameter.kind === 'switch') {
151
+ if (parameter.kind === 'range') {
152
+ const type = validated.bindTypes.get(syqlRangeStartBind(parameter.name));
153
+ if (type === undefined) {
154
+ return fail('SYQL7002_INTERNAL_LOWERING', query, `range ${parameter.name} has no resolved element type`);
155
+ }
164
156
  return {
165
- kind: 'switch',
157
+ kind: 'group',
166
158
  name: parameter.name,
167
159
  langName,
168
- default: false,
160
+ members: [
161
+ {
162
+ name: 'start',
163
+ langName: 'start',
164
+ type: type.base,
165
+ nullable: type.nullable,
166
+ },
167
+ {
168
+ name: 'end',
169
+ langName: 'end',
170
+ type: type.base,
171
+ nullable: type.nullable,
172
+ },
173
+ ],
169
174
  };
170
175
  }
171
176
  if (parameter.kind === 'group') {
@@ -199,7 +204,10 @@ function publicInputs(validated, naming) {
199
204
  langName,
200
205
  type: type.base,
201
206
  nullable: type.nullable,
202
- required: !parameter.optional,
207
+ required: !parameter.optional && parameter.default === undefined,
208
+ ...(parameter.default === undefined
209
+ ? {}
210
+ : { default: parameter.default }),
203
211
  };
204
212
  });
205
213
  if (validated.sort !== undefined) {
@@ -215,13 +223,13 @@ function publicInputs(validated, naming) {
215
223
  })),
216
224
  });
217
225
  }
218
- if (validated.page !== undefined) {
226
+ if (validated.limit !== undefined) {
219
227
  result.push({
220
- kind: 'page',
221
- name: validated.page.control,
222
- langName: mapped.get(validated.page.control),
223
- defaultSize: validated.page.defaultSize,
224
- maxSize: validated.page.maxSize,
228
+ kind: 'limit',
229
+ name: validated.limit.control,
230
+ langName: mapped.get(validated.limit.control),
231
+ defaultSize: validated.limit.defaultSize,
232
+ maxSize: validated.limit.maxSize,
225
233
  });
226
234
  }
227
235
  return result;
@@ -229,9 +237,23 @@ function publicInputs(validated, naming) {
229
237
  function valueOwners(validated) {
230
238
  const owners = new Map();
231
239
  for (const parameter of validated.logical.declaration.parameters) {
232
- if (parameter.kind === 'switch')
233
- continue;
234
- if (parameter.kind === 'group') {
240
+ if (parameter.kind === 'range') {
241
+ for (const [name, member] of [
242
+ [syqlRangeStartBind(parameter.name), 'start'],
243
+ [syqlRangeEndBind(parameter.name), 'end'],
244
+ ]) {
245
+ const type = validated.bindTypes.get(name);
246
+ if (type === undefined)
247
+ continue;
248
+ owners.set(name, {
249
+ kind: 'group-member',
250
+ input: parameter.name,
251
+ member,
252
+ type: type.base,
253
+ });
254
+ }
255
+ }
256
+ else if (parameter.kind === 'group') {
235
257
  for (const member of parameter.members) {
236
258
  const type = validated.bindTypes.get(member.name);
237
259
  if (type === undefined)
@@ -267,13 +289,14 @@ function lowerStatement(validated, ir, db, naming, sql, sortProfile, activationM
267
289
  const query = validated.logical;
268
290
  const location = `${query.module.file} (query ${query.declaration.name}, generated)`;
269
291
  const names = distinctBindNames(sql, location);
270
- const headers = headersFor(names, owners, conditionBinds, validated.page, query);
292
+ const headers = headersFor(names, owners, conditionBinds, validated.limit, query);
271
293
  const candidate = headers.length === 0 ? sql : `${headers}\n${sql}`;
272
294
  const analyzed = analyzeStatement(query.declaration.name, location, candidate, ir, db, {
273
295
  ...naming,
274
296
  internalParams: [
275
297
  ...conditionBinds.keys(),
276
- ...(validated.page === undefined ? [] : [PAGE_BIND]),
298
+ ...(validated.limit === undefined ? [] : [LIMIT_BIND]),
299
+ ...[...owners.keys()].filter((name) => name.startsWith('__syqlRange')),
277
300
  ],
278
301
  });
279
302
  const namedSql = headers.length === 0
@@ -286,7 +309,7 @@ function lowerStatement(validated, ir, db, naming, sql, sortProfile, activationM
286
309
  ...(activationMask === undefined ? {} : { activationMask }),
287
310
  sql: namedSql,
288
311
  positionalSql: analyzed.positionalSql,
289
- binds: bindNames.map((name) => planBind(name, owners, conditionBinds, query.conditions, validated.page, query)),
312
+ binds: bindNames.map((name) => planBind(name, owners, conditionBinds, query.conditions, validated.limit, query)),
290
313
  },
291
314
  analysis: { ...analyzed, sourceSql: namedSql, sql: namedSql },
292
315
  };
@@ -315,7 +338,7 @@ export function lowerSyqlQuery(validated, ir, db, naming = DEFAULT_NAMING, optio
315
338
  const body = renderTemplate(logical.template, conditions, {
316
339
  kind: 'neutralized',
317
340
  });
318
- const sql = composeControls(body, logical.module.file, profile.sql, validated.page);
341
+ const sql = composeControls(body, logical.module.file, profile.sql, validated.limit);
319
342
  const lowered = lowerStatement(validated, ir, db, naming, sql, profile.name, undefined, owners, conditionBinds);
320
343
  neutralStatements.push(lowered.statement);
321
344
  if (neutralDefault === undefined ||
@@ -347,7 +370,7 @@ export function lowerSyqlQuery(validated, ir, db, naming = DEFAULT_NAMING, optio
347
370
  kind: 'enumerated',
348
371
  active,
349
372
  });
350
- const sql = composeControls(body, logical.module.file, profile.sql, validated.page);
373
+ const sql = composeControls(body, logical.module.file, profile.sql, validated.limit);
351
374
  const lowered = lowerStatement(validated, ir, db, naming, sql, profile.name, mask, owners, new Map());
352
375
  statements.push(lowered.statement);
353
376
  if (mask === 0 &&
@@ -12,13 +12,17 @@ export interface SyqlValueParameter {
12
12
  readonly name: string;
13
13
  readonly optional: boolean;
14
14
  readonly type?: SyqlValueType;
15
+ /** A source-level default. Revision 1 currently permits only `bool = false`. */
16
+ readonly default?: false;
15
17
  readonly span: SyqlSourceSpan;
16
18
  readonly nameSpan: SyqlSourceSpan;
17
19
  }
18
- export interface SyqlSwitchParameter {
19
- readonly kind: 'switch';
20
+ export interface SyqlRangeParameter {
21
+ readonly kind: 'range';
20
22
  readonly name: string;
21
- readonly optional: true;
23
+ readonly optional: boolean;
24
+ /** Element type, inferred from the left side of BETWEEN when omitted. */
25
+ readonly type?: SyqlValueType;
22
26
  readonly span: SyqlSourceSpan;
23
27
  readonly nameSpan: SyqlSourceSpan;
24
28
  }
@@ -36,7 +40,7 @@ export interface SyqlGroupParameter {
36
40
  readonly span: SyqlSourceSpan;
37
41
  readonly nameSpan: SyqlSourceSpan;
38
42
  }
39
- export type SyqlQueryParameter = SyqlValueParameter | SyqlSwitchParameter | SyqlGroupParameter;
43
+ export type SyqlQueryParameter = SyqlValueParameter | SyqlRangeParameter | SyqlGroupParameter;
40
44
  export interface SyqlPredicateParameter {
41
45
  readonly name: string;
42
46
  readonly type?: SyqlValueType;
@@ -72,11 +76,6 @@ export interface SyqlPredicateDeclaration {
72
76
  readonly span: SyqlSourceSpan;
73
77
  readonly nameSpan: SyqlSourceSpan;
74
78
  }
75
- export interface SyqlSqlSection {
76
- readonly kind: 'sql';
77
- readonly body: SyqlTemplate;
78
- readonly span: SyqlSourceSpan;
79
- }
80
79
  export interface SyqlSortProfile {
81
80
  readonly name: string;
82
81
  readonly order: SyqlTemplate;
@@ -91,27 +90,29 @@ export interface SyqlSortSection {
91
90
  readonly span: SyqlSourceSpan;
92
91
  readonly controlSpan: SyqlSourceSpan;
93
92
  }
94
- export interface SyqlPageDeclaration {
95
- readonly kind: 'page';
93
+ export interface SyqlLimitDeclaration {
94
+ readonly kind: 'limit';
96
95
  readonly control: string;
97
96
  readonly defaultSize: number;
98
97
  readonly maxSize: number;
99
98
  readonly span: SyqlSourceSpan;
100
99
  readonly controlSpan: SyqlSourceSpan;
101
100
  }
102
- export interface SyqlIdentityDeclaration {
103
- readonly kind: 'identity';
104
- readonly fields: readonly string[];
101
+ export interface SyqlSyncDimension {
102
+ readonly qualifier: string;
103
+ readonly column: string;
105
104
  readonly span: SyqlSourceSpan;
106
105
  }
107
106
  export interface SyqlQueryDeclaration {
108
107
  readonly kind: 'query';
109
108
  readonly name: string;
109
+ readonly sync: boolean;
110
+ readonly syncBy?: SyqlSyncDimension;
110
111
  readonly parameters: readonly SyqlQueryParameter[];
111
- readonly sql: SyqlSqlSection;
112
+ /** The SQL-shaped statement body, excluding its terminating semicolon. */
113
+ readonly statement: SyqlTemplate;
112
114
  readonly sort?: SyqlSortSection;
113
- readonly page?: SyqlPageDeclaration;
114
- readonly identity?: SyqlIdentityDeclaration;
115
+ readonly limit?: SyqlLimitDeclaration;
115
116
  readonly span: SyqlSourceSpan;
116
117
  readonly nameSpan: SyqlSourceSpan;
117
118
  }
@@ -127,6 +128,6 @@ export interface SyqlSyntaxFile {
127
128
  readonly queries: readonly SyqlQueryDeclaration[];
128
129
  readonly span: SyqlSourceSpan;
129
130
  }
130
- export type SyqlParseErrorCode = 'SYQL2001_EXPECTED_TOKEN' | 'SYQL2002_INVALID_NAME' | 'SYQL2003_RESERVED_NAME' | 'SYQL2004_DUPLICATE_NAME' | 'SYQL2005_INVALID_IMPORT' | 'SYQL2006_EMPTY_TEMPLATE' | 'SYQL2007_FORBIDDEN_SEMICOLON' | 'SYQL2008_INVALID_MEMBER' | 'SYQL2009_INVALID_INTEGER' | 'SYQL2010_INVALID_PAGE_RANGE' | 'SYQL2011_INVALID_PARAMETER';
131
+ export type SyqlParseErrorCode = 'SYQL2001_EXPECTED_TOKEN' | 'SYQL2002_INVALID_NAME' | 'SYQL2003_RESERVED_NAME' | 'SYQL2004_DUPLICATE_NAME' | 'SYQL2005_INVALID_IMPORT' | 'SYQL2006_EMPTY_TEMPLATE' | 'SYQL2007_FORBIDDEN_SEMICOLON' | 'SYQL2008_INVALID_MEMBER' | 'SYQL2009_INVALID_INTEGER' | 'SYQL2010_INVALID_PAGE_RANGE' | 'SYQL2011_INVALID_PARAMETER' | 'SYQL2012_INVALID_QUERY_BODY';
131
132
  /** Parse one `.syql` file using the destructive revision-1 grammar. */
132
133
  export declare function parseSyqlSyntaxFile(file: string, source: string): SyqlSyntaxFile;