@hypequery/datasets 0.13.6 → 0.14.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.
Files changed (107) hide show
  1. package/README.md +10 -0
  2. package/dist/agent-catalog.d.ts +97 -0
  3. package/dist/agent-catalog.d.ts.map +1 -0
  4. package/dist/agent-catalog.js +79 -0
  5. package/dist/api.type-test.js +19 -1
  6. package/dist/catalog.d.ts +17 -6
  7. package/dist/catalog.d.ts.map +1 -1
  8. package/dist/catalog.js +18 -1
  9. package/dist/contract.d.ts +11 -7
  10. package/dist/contract.d.ts.map +1 -1
  11. package/dist/contract.js +22 -1
  12. package/dist/dataset-query.js +1 -1
  13. package/dist/dataset.d.ts.map +1 -1
  14. package/dist/dataset.js +19 -2
  15. package/dist/executor.d.ts +6 -0
  16. package/dist/executor.d.ts.map +1 -1
  17. package/dist/executor.js +55 -23
  18. package/dist/field.d.ts.map +1 -1
  19. package/dist/field.js +2 -0
  20. package/dist/index.d.ts +10 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +7 -0
  23. package/dist/measure.d.ts.map +1 -1
  24. package/dist/measure.js +4 -0
  25. package/dist/protocol-adapter.d.ts.map +1 -1
  26. package/dist/protocol-adapter.js +21 -0
  27. package/dist/protocol-rehydrate.d.ts +46 -0
  28. package/dist/protocol-rehydrate.d.ts.map +1 -0
  29. package/dist/protocol-rehydrate.js +218 -0
  30. package/dist/publishing/features/dataset-publication.d.ts +10 -0
  31. package/dist/publishing/features/dataset-publication.d.ts.map +1 -0
  32. package/dist/publishing/features/dataset-publication.js +34 -0
  33. package/dist/publishing/node.d.ts +16 -0
  34. package/dist/publishing/node.d.ts.map +1 -0
  35. package/dist/publishing/node.js +35 -0
  36. package/dist/publishing/publisher.d.ts +17 -0
  37. package/dist/publishing/publisher.d.ts.map +1 -0
  38. package/dist/publishing/publisher.js +32 -0
  39. package/dist/publishing/types.d.ts +31 -0
  40. package/dist/publishing/types.d.ts.map +1 -0
  41. package/dist/publishing/types.js +1 -0
  42. package/dist/query-builder-protocol.d.ts +6 -2
  43. package/dist/query-builder-protocol.d.ts.map +1 -1
  44. package/dist/semantic-plan.d.ts +3 -1
  45. package/dist/semantic-plan.d.ts.map +1 -1
  46. package/dist/semantic-planner.d.ts.map +1 -1
  47. package/dist/semantic-planner.js +4 -0
  48. package/dist/semantic-query-schema.d.ts +48 -0
  49. package/dist/semantic-query-schema.d.ts.map +1 -0
  50. package/dist/semantic-query-schema.js +218 -0
  51. package/dist/sql-utils.d.ts +36 -0
  52. package/dist/sql-utils.d.ts.map +1 -1
  53. package/dist/sql-utils.js +76 -0
  54. package/dist/tools.d.ts +5 -0
  55. package/dist/tools.d.ts.map +1 -1
  56. package/dist/tools.js +25 -267
  57. package/dist/types.d.ts +98 -8
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/utils/agent-catalog-projection.d.ts +78 -0
  60. package/dist/utils/agent-catalog-projection.d.ts.map +1 -0
  61. package/dist/utils/agent-catalog-projection.js +179 -0
  62. package/dist/utils/dataset-cache-policy.d.ts +34 -0
  63. package/dist/utils/dataset-cache-policy.d.ts.map +1 -0
  64. package/dist/utils/dataset-cache-policy.js +50 -0
  65. package/dist/utils/dataset-contract.d.ts +2 -2
  66. package/dist/utils/dataset-contract.d.ts.map +1 -1
  67. package/dist/utils/dataset-contract.js +3 -1
  68. package/dist/utils/dataset-definition-validation.d.ts +35 -0
  69. package/dist/utils/dataset-definition-validation.d.ts.map +1 -0
  70. package/dist/utils/dataset-definition-validation.js +215 -0
  71. package/dist/utils/dataset-metric-ref.d.ts +2 -2
  72. package/dist/utils/dataset-metric-ref.d.ts.map +1 -1
  73. package/dist/utils/dataset-metric-ref.js +5 -3
  74. package/dist/utils/metric-alias.d.ts +4 -0
  75. package/dist/utils/metric-alias.d.ts.map +1 -0
  76. package/dist/utils/metric-alias.js +28 -0
  77. package/dist/utils/protocol-metric-capabilities.d.ts +7 -0
  78. package/dist/utils/protocol-metric-capabilities.d.ts.map +1 -0
  79. package/dist/utils/protocol-metric-capabilities.js +57 -0
  80. package/dist/utils/protocol-rehydrate-filters.d.ts +10 -0
  81. package/dist/utils/protocol-rehydrate-filters.d.ts.map +1 -0
  82. package/dist/utils/protocol-rehydrate-filters.js +36 -0
  83. package/dist/utils/protocol-semantic-metadata.d.ts +5 -0
  84. package/dist/utils/protocol-semantic-metadata.d.ts.map +1 -0
  85. package/dist/utils/protocol-semantic-metadata.js +5 -0
  86. package/dist/utils/published-name.d.ts +3 -0
  87. package/dist/utils/published-name.d.ts.map +1 -0
  88. package/dist/utils/published-name.js +7 -0
  89. package/dist/utils/published-relationships.d.ts +34 -0
  90. package/dist/utils/published-relationships.d.ts.map +1 -0
  91. package/dist/utils/published-relationships.js +35 -0
  92. package/dist/utils/relationship-fields.d.ts +7 -0
  93. package/dist/utils/relationship-fields.d.ts.map +1 -1
  94. package/dist/utils/relationship-fields.js +13 -1
  95. package/dist/utils/result-limits.d.ts +34 -0
  96. package/dist/utils/result-limits.d.ts.map +1 -0
  97. package/dist/utils/result-limits.js +40 -0
  98. package/dist/utils/semantic-metadata-validation.d.ts +4 -0
  99. package/dist/utils/semantic-metadata-validation.d.ts.map +1 -0
  100. package/dist/utils/semantic-metadata-validation.js +103 -0
  101. package/dist/utils/semantic-metadata.d.ts +4 -0
  102. package/dist/utils/semantic-metadata.d.ts.map +1 -0
  103. package/dist/utils/semantic-metadata.js +13 -0
  104. package/dist/utils/semantic-tool.d.ts +5 -0
  105. package/dist/utils/semantic-tool.d.ts.map +1 -0
  106. package/dist/utils/semantic-tool.js +29 -0
  107. package/package.json +5 -4
@@ -0,0 +1,218 @@
1
+ import { sha256 } from '@noble/hashes/sha2';
2
+ import { bytesToHex } from '@noble/hashes/utils';
3
+ import { z } from 'zod';
4
+ import { zodToJsonSchema } from 'zod-to-json-schema';
5
+ import { getDatasetCatalog, getGroupableRelationshipFields, getQueryableRelationshipFields, } from './catalog.js';
6
+ import { SEMANTIC_FILTER_OPERATORS } from './constants.js';
7
+ import { compareStrings, stableStringify, uniqueSorted } from './utils/canonical-json.js';
8
+ export const DEFAULT_SEMANTIC_QUERY_SCHEMA_LIMITS = Object.freeze({
9
+ maxResultSize: 10_000,
10
+ maxOffset: 10_000,
11
+ maxDimensions: 50,
12
+ maxMeasures: 50,
13
+ maxFilters: 100,
14
+ maxOrderBy: 50,
15
+ });
16
+ function isDatasetCatalog(source) {
17
+ return 'requiresTenant' in source && 'supportedGrains' in source && 'orderableFields' in source;
18
+ }
19
+ function resolveCatalog(source) {
20
+ return isDatasetCatalog(source)
21
+ ? source
22
+ : getDatasetCatalog(source);
23
+ }
24
+ function lowerLimit(...values) {
25
+ const finite = values.filter((value) => value !== undefined);
26
+ return finite.length > 0 ? Math.min(...finite) : undefined;
27
+ }
28
+ function fieldEnum(values) {
29
+ const unique = uniqueSorted(values);
30
+ return unique.length > 0
31
+ ? z.enum(unique)
32
+ : z.never();
33
+ }
34
+ function boundedArray(item, maximum) {
35
+ const array = z.array(item);
36
+ return (maximum === undefined ? array : array.max(maximum)).optional();
37
+ }
38
+ function filterSchema(catalog, fields) {
39
+ const filterValue = z.unknown().refine(value => value !== undefined, 'Required');
40
+ const relationshipFields = new Set(getQueryableRelationshipFields(catalog));
41
+ const variants = uniqueSorted(fields).map((field) => z.object({
42
+ field: z.literal(field),
43
+ operator: relationshipFields.has(field)
44
+ ? z.enum(SEMANTIC_FILTER_OPERATORS)
45
+ : fieldEnum(catalog.filters[field]?.operators ?? [...SEMANTIC_FILTER_OPERATORS]),
46
+ value: filterValue,
47
+ }).strict());
48
+ if (variants.length === 0) {
49
+ return z.object({
50
+ field: z.never(),
51
+ operator: z.enum(SEMANTIC_FILTER_OPERATORS),
52
+ value: filterValue,
53
+ }).strict();
54
+ }
55
+ if (variants.length === 1)
56
+ return variants[0];
57
+ return z.union(variants);
58
+ }
59
+ function queryShape(catalog, metricName, options, metric, localRelationshipFields = []) {
60
+ const limits = { ...DEFAULT_SEMANTIC_QUERY_SCHEMA_LIMITS, ...options };
61
+ const relationshipFields = getQueryableRelationshipFields(catalog);
62
+ // `groupable: false` declares a dimension that exists to back a measure, not
63
+ // to be selected. The agent-safe catalog already hides those, so the
64
+ // generated schema must refuse them too — otherwise a dataset advertises one
65
+ // set of dimensions and accepts another. This holds across a relationship
66
+ // hop: a non-groupable target dimension stays filterable but is not a
67
+ // grouping key, so the two lists are tracked separately.
68
+ const groupableRelationshipFields = new Set(getGroupableRelationshipFields(catalog));
69
+ const isGroupable = (name) => (catalog.dimensions[name] !== undefined
70
+ ? catalog.dimensions[name].groupable !== false
71
+ : groupableRelationshipFields.has(name));
72
+ const dimensions = metric
73
+ ? uniqueSorted([
74
+ ...metric.dimensions.filter(isGroupable),
75
+ ...localRelationshipFields.filter(isGroupable),
76
+ ])
77
+ : uniqueSorted([
78
+ ...Object.keys(catalog.dimensions).filter(isGroupable),
79
+ ...relationshipFields.filter(isGroupable),
80
+ ]);
81
+ const declaredFilters = Object.keys(catalog.filters);
82
+ const filterFields = metric
83
+ ? uniqueSorted([...metric.filters, ...localRelationshipFields])
84
+ : metricName
85
+ ? uniqueSorted([
86
+ ...(declaredFilters.length > 0 ? declaredFilters : Object.keys(catalog.dimensions)),
87
+ ...relationshipFields,
88
+ ])
89
+ : uniqueSorted([...declaredFilters, ...relationshipFields]);
90
+ const grains = metric
91
+ ? metric.grain ? [metric.grain] : metric.grains
92
+ : catalog.supportedGrains;
93
+ const orderable = metricName
94
+ ? uniqueSorted([...dimensions, metricName, ...(grains.length > 0 ? ['period'] : [])])
95
+ : uniqueSorted([
96
+ ...dimensions,
97
+ ...Object.keys(catalog.measures),
98
+ ...(catalog.supportedGrains.length > 0 ? ['period'] : []),
99
+ ]);
100
+ const maxResultSize = options.enforceResultLimit === false
101
+ ? undefined
102
+ : lowerLimit(catalog.limits?.maxResultSize, limits.maxResultSize);
103
+ const defaultResultSize = options.defaultResultSize === undefined
104
+ ? undefined
105
+ : lowerLimit(options.defaultResultSize, maxResultSize);
106
+ const grainField = options.grainField ?? 'by';
107
+ const limitSchema = maxResultSize === undefined
108
+ ? z.number().int().positive()
109
+ : z.number().int().positive().max(maxResultSize);
110
+ return {
111
+ dimensions: boundedArray(fieldEnum(dimensions), lowerLimit(catalog.limits?.maxDimensions, limits.maxDimensions)),
112
+ ...(metricName ? {} : {
113
+ measures: boundedArray(fieldEnum(Object.keys(catalog.measures)), lowerLimit(catalog.limits?.maxMeasures, limits.maxMeasures)),
114
+ }),
115
+ filters: boundedArray(filterSchema(catalog, filterFields), lowerLimit(catalog.limits?.maxFilters, limits.maxFilters)),
116
+ orderBy: boundedArray(z.object({
117
+ field: fieldEnum(orderable),
118
+ direction: z.enum(['asc', 'desc']),
119
+ }).strict(), limits.maxOrderBy),
120
+ limit: defaultResultSize === undefined
121
+ ? limitSchema.optional()
122
+ : limitSchema.default(defaultResultSize),
123
+ offset: (limits.maxOffset === undefined
124
+ ? z.number().int().nonnegative()
125
+ : z.number().int().nonnegative().max(limits.maxOffset)).optional(),
126
+ [grainField]: fieldEnum(grains).optional(),
127
+ ...(options.includeMeta ? { includeMeta: z.boolean().optional() } : {}),
128
+ };
129
+ }
130
+ export function buildDatasetInputSchema(dataset, options = {}) {
131
+ const schema = z.object(queryShape(resolveCatalog(dataset), undefined, options)).strict();
132
+ if (options.requireSelection === false)
133
+ return schema;
134
+ return schema.refine(input => (input.dimensions?.length ?? 0) > 0 || (input.measures?.length ?? 0) > 0, { message: 'At least one dimension or measure must be specified' });
135
+ }
136
+ export function buildMetricInputSchema(dataset, metricName, options = {}, metricContract) {
137
+ const catalog = resolveCatalog(dataset);
138
+ const metric = metricContract ?? catalog.metrics[metricName];
139
+ const localRelationshipFields = isDatasetCatalog(dataset)
140
+ ? []
141
+ : getQueryableRelationshipFields(catalog);
142
+ return z.object(queryShape(catalog, metricName, options, metric, localRelationshipFields)).strict();
143
+ }
144
+ function unionSchemas(schemas, emptyShape) {
145
+ if (schemas.length === 0)
146
+ return z.object(emptyShape).strict();
147
+ if (schemas.length === 1)
148
+ return schemas[0];
149
+ return z.union(schemas);
150
+ }
151
+ function withSelectors(schema, selectors, requireSelection) {
152
+ const shape = (schema instanceof z.ZodEffects ? schema.innerType() : schema).shape;
153
+ const selected = z.object({ ...selectors, ...shape }).strict();
154
+ if (!requireSelection)
155
+ return selected;
156
+ return selected.refine(input => (input.dimensions?.length ?? 0) > 0 || (input.measures?.length ?? 0) > 0, { message: 'At least one dimension or measure must be specified' });
157
+ }
158
+ export function toSemanticJsonSchema(schema, options = {}) {
159
+ const converted = zodToJsonSchema(schema, { target: 'jsonSchema7', $refStrategy: 'none' });
160
+ const { $schema: _schema, ...jsonSchema } = converted;
161
+ const result = jsonSchema;
162
+ const objectSchema = result.anyOf && !result.type ? { ...result, type: 'object' } : result;
163
+ return options.requireSelection ? addSelectionRequirement(objectSchema) : objectSchema;
164
+ }
165
+ function addSelectionRequirement(schema) {
166
+ return {
167
+ ...schema,
168
+ allOf: [
169
+ ...(schema.allOf ?? []),
170
+ {
171
+ anyOf: [
172
+ {
173
+ type: 'object',
174
+ properties: { dimensions: { type: 'array', minItems: 1 } },
175
+ required: ['dimensions'],
176
+ },
177
+ {
178
+ type: 'object',
179
+ properties: { measures: { type: 'array', minItems: 1 } },
180
+ required: ['measures'],
181
+ },
182
+ ],
183
+ },
184
+ ],
185
+ };
186
+ }
187
+ export function buildCanonicalSemanticQuerySchemas(datasets, options = {}) {
188
+ const datasetSchemas = [];
189
+ const metricSchemas = [];
190
+ for (const [datasetName, dataset] of Object.entries(datasets)
191
+ .sort(([left], [right]) => compareStrings(left, right))) {
192
+ datasetSchemas.push(withSelectors(buildDatasetInputSchema(dataset, { ...options, requireSelection: false }), { dataset: z.literal(datasetName) }, options.requireSelection !== false));
193
+ const catalog = resolveCatalog(dataset);
194
+ for (const metricName of Object.keys(catalog.metrics).sort(compareStrings)) {
195
+ metricSchemas.push(withSelectors(buildMetricInputSchema(dataset, metricName, options, catalog.metrics[metricName]), { dataset: z.literal(datasetName), metric: z.literal(metricName) }, false));
196
+ }
197
+ }
198
+ const queryDataset = unionSchemas(datasetSchemas, { dataset: z.never() });
199
+ const queryMetric = unionSchemas(metricSchemas, {
200
+ dataset: z.never(),
201
+ metric: z.never(),
202
+ });
203
+ const queryDatasetJsonSchema = toSemanticJsonSchema(queryDataset, {
204
+ requireSelection: options.requireSelection !== false,
205
+ });
206
+ const queryMetricJsonSchema = toSemanticJsonSchema(queryMetric);
207
+ const manifestHash = bytesToHex(sha256(new TextEncoder().encode(stableStringify({
208
+ query_dataset: queryDatasetJsonSchema,
209
+ query_metric: queryMetricJsonSchema,
210
+ }))));
211
+ return Object.freeze({
212
+ queryDataset,
213
+ queryMetric,
214
+ queryDatasetJsonSchema,
215
+ queryMetricJsonSchema,
216
+ manifestHash,
217
+ });
218
+ }
@@ -25,4 +25,40 @@ export declare function validateSQLIdentifier(identifier: string, context: strin
25
25
  * @returns Quoted identifier
26
26
  */
27
27
  export declare function quoteSQLIdentifier(identifier: string): string;
28
+ export interface StripSqlLiteralsOptions {
29
+ /**
30
+ * Keep the text inside quoted identifiers (`` `col` ``, `"col"`), blanking only
31
+ * the delimiters. String literals are blanked either way.
32
+ *
33
+ * The two callers need different views of the same expression. Finding a
34
+ * statement terminator means finding one that is *syntax*, and a `;` inside
35
+ * `` `odd;name` `` is not — so that check blanks quoted identifiers too.
36
+ * Deciding whether an expression references a column is the opposite: a quoted
37
+ * identifier is exactly such a reference, so that check needs its text.
38
+ */
39
+ readonly keepQuotedIdentifiers?: boolean;
40
+ }
41
+ /**
42
+ * Blanks out quoted spans in a SQL expression, preserving length and structure.
43
+ *
44
+ * Lexical checks that look for statement terminators or comment openers have to
45
+ * run on code rather than on data: `concat(name, '; ')` and
46
+ * `replaceAll(note, '--', '')` are ordinary expressions whose literals happen to
47
+ * contain those characters. Scanning the raw source text rejects them.
48
+ *
49
+ * Both ClickHouse escape forms are handled: a doubled quote (`'it''s'`) and a
50
+ * backslash escape (`'it\'s'`).
51
+ *
52
+ * @throws Error when a quote is never closed — an unterminated literal is
53
+ * malformed on its own, and treating the remainder as data would let an open
54
+ * quote hide anything after it.
55
+ */
56
+ export declare function stripSqlLiterals(sql: string, options?: StripSqlLiteralsOptions): string;
57
+ /**
58
+ * Escapes a string for literal use inside a regular expression.
59
+ *
60
+ * Without this, a value carrying regex syntax either throws at `RegExp`
61
+ * construction or silently matches something other than itself.
62
+ */
63
+ export declare function escapeRegExp(value: string): string;
28
64
  //# sourceMappingURL=sql-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sql-utils.d.ts","sourceRoot":"","sources":["../src/sql-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAO/E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAI7D"}
1
+ {"version":3,"file":"sql-utils.d.ts","sourceRoot":"","sources":["../src/sql-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAO/E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAI7D;AAQD,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;OASG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC1C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,MAAM,CAoDvF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD"}
package/dist/sql-utils.js CHANGED
@@ -36,3 +36,79 @@ export function quoteSQLIdentifier(identifier) {
36
36
  const escaped = identifier.replace(/`/g, '``');
37
37
  return `\`${escaped}\``;
38
38
  }
39
+ /** Quote characters that open a literal or a quoted identifier in ClickHouse. */
40
+ const SQL_QUOTES = new Set(["'", '"', '`']);
41
+ /** Quotes that delimit an identifier rather than a string literal. */
42
+ const IDENTIFIER_QUOTES = new Set(['"', '`']);
43
+ /**
44
+ * Blanks out quoted spans in a SQL expression, preserving length and structure.
45
+ *
46
+ * Lexical checks that look for statement terminators or comment openers have to
47
+ * run on code rather than on data: `concat(name, '; ')` and
48
+ * `replaceAll(note, '--', '')` are ordinary expressions whose literals happen to
49
+ * contain those characters. Scanning the raw source text rejects them.
50
+ *
51
+ * Both ClickHouse escape forms are handled: a doubled quote (`'it''s'`) and a
52
+ * backslash escape (`'it\'s'`).
53
+ *
54
+ * @throws Error when a quote is never closed — an unterminated literal is
55
+ * malformed on its own, and treating the remainder as data would let an open
56
+ * quote hide anything after it.
57
+ */
58
+ export function stripSqlLiterals(sql, options) {
59
+ let output = '';
60
+ let index = 0;
61
+ while (index < sql.length) {
62
+ const char = sql[index];
63
+ if (!SQL_QUOTES.has(char)) {
64
+ output += char;
65
+ index += 1;
66
+ continue;
67
+ }
68
+ const quote = char;
69
+ let cursor = index + 1;
70
+ let closed = false;
71
+ while (cursor < sql.length) {
72
+ const current = sql[cursor];
73
+ if (current === '\\') {
74
+ // Backslash escapes the next character, whatever it is.
75
+ cursor += 2;
76
+ continue;
77
+ }
78
+ if (current === quote) {
79
+ if (sql[cursor + 1] === quote) {
80
+ // A doubled quote is an escaped quote, not the end of the span.
81
+ cursor += 2;
82
+ continue;
83
+ }
84
+ closed = true;
85
+ cursor += 1;
86
+ break;
87
+ }
88
+ cursor += 1;
89
+ }
90
+ if (!closed) {
91
+ throw new Error(`Unterminated ${quote} literal in SQL expression.`);
92
+ }
93
+ if (options?.keepQuotedIdentifiers && IDENTIFIER_QUOTES.has(quote)) {
94
+ // Blank only the delimiters, so the identifier stays readable as the
95
+ // column reference it is. Length is preserved either way.
96
+ output += ` ${sql.slice(index + 1, cursor - 1)} `;
97
+ }
98
+ else {
99
+ // Replace the whole span, quotes included, with spaces so offsets survive.
100
+ output += ' '.repeat(cursor - index);
101
+ }
102
+ index = cursor;
103
+ }
104
+ return output;
105
+ }
106
+ /**
107
+ * Escapes a string for literal use inside a regular expression.
108
+ *
109
+ * Without this, a value carrying regex syntax either throws at `RegExp`
110
+ * construction or silently matches something other than itself.
111
+ */
112
+ export function escapeRegExp(value) {
113
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
114
+ }
package/dist/tools.d.ts CHANGED
@@ -10,6 +10,11 @@ export type JsonSchema = {
10
10
  minimum?: number;
11
11
  maximum?: number;
12
12
  additionalProperties?: boolean;
13
+ minItems?: number;
14
+ maxItems?: number;
15
+ anyOf?: JsonSchema[];
16
+ allOf?: JsonSchema[];
17
+ const?: string;
13
18
  };
14
19
  export interface SemanticToolDefinition<TInput = Record<string, unknown>, TResult = unknown> {
15
20
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EAGZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EAKjB,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AAGtB,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtE;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,OAAO,CACL,MAAM,EAAE,kBAAkB,GAAG,YAAY,EACzC,KAAK,CAAC,EAAE,YAAY,GAAG,WAAW,EAClC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC/C,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,UAAU,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;CACzB;AAoXD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,sBAAsB,EAAE,CAenG;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,oBAAoB,EAAE,CASrF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAWjG;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,iBAAiB,EAAE,CAM/E;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}