@tellaro/tql 2.0.0 → 3.0.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/index.js CHANGED
@@ -1,73 +1,78 @@
1
- import { AGGREGATION_FUNCTIONS as r, BOOLEAN_PREDICATE_MUTATORS as i, BOOLEAN_PREDICATE_MUTATOR_SET as o, COLLECTION_OPERATORS as T, COMPARISON_OPERATORS as a, KEYWORDS as l, LOGICAL_OPERATORS as n, MUTATORS as g, NEGATION_SYMBOL_OPERATORS as s, SYMBOL_OPERATORS as O, TYPE_HINTS as m, TqlTokenizer as A, VISUALIZATION_TYPES as c, findPreviousToken as E, findTokenAtPosition as S, findTokenBefore as p, findTokensInRange as C, tokenizeTql as d, tokenizeTqlNoWhitespace as f } from "./src/tokenizer.js";
2
- import { TqlParser as h, formatParseError as P, getTqlErrors as _, isValidTql as N, parseTql as x } from "./src/parser.js";
3
- import { MAX_REGEX_PATTERN_LENGTH as I, TqlValidator as y, formatValidationResult as q, getTqlIssues as M, isValidTqlSyntax as u, validateTql as z } from "./src/validator.js";
4
- import { getCompletionTriggerCharacters as F, getCompletions as G, getWordAtPosition as U, shouldTriggerCompletion as V } from "./src/completionProvider.js";
5
- import { findClosestMatch as B, fuzzyFilter as D, fuzzyMatch as Y, highlightMatch as H, levenshteinDistance as W } from "./src/fuzzyMatcher.js";
6
- import { SchemaCache as X, createSchemaCache as b, getCachedField as K, getCachedFieldNames as Q, getCachedFieldType as Z, getSchemaCache as j } from "./src/schemaCache.js";
7
- import { ComplexityAnalyzer as $, analyzeComplexity as ee, getComplexityMetrics as te, getComplexityWarnings as re, isHighComplexity as ie } from "./src/complexityAnalyzer.js";
8
- import { SemanticPreview as Te, flattenLogicTree as ae, formatLogicTreeAscii as le, formatLogicTreeNode as ne, generatePreview as ge, getFieldUsage as se, getLogicTree as Oe, getLogicTreeDepth as me, getOperatorSummary as Ae, getUniqueFields as ce } from "./src/semanticPreview.js";
9
- import { buildStatsQuery as Se, parseVizHintString as pe } from "./src/builder.js";
1
+ import { AGGREGATION_FUNCTIONS as r, BOOLEAN_PREDICATE_MUTATORS as i, BOOLEAN_PREDICATE_MUTATOR_SET as o, COLLECTION_OPERATORS as T, COMPARISON_OPERATORS as a, KEYWORDS as E, LOGICAL_OPERATORS as l, MUTATORS as S, NEGATION_SYMBOL_OPERATORS as O, SYMBOL_OPERATORS as n, TYPE_HINTS as s, TqlTokenizer as g, VISUALIZATION_TYPES as A, findPreviousToken as m, findTokenAtPosition as R, findTokenBefore as c, findTokensInRange as C, tokenizeTql as _, tokenizeTqlNoWhitespace as p } from "./src/tokenizer.js";
2
+ import { TqlParser as d, formatParseError as f, getTqlErrors as h, isValidTql as I, parseTql as N } from "./src/parser.js";
3
+ import { CASE_SENSITIVE_MEMBERSHIP_OPERATORS as x, CASE_SENSITIVE_OPERATORS as y, CASE_SENSITIVE_WHOLE_VALUE_OPERATORS as M, MAX_REGEX_PATTERN_LENGTH as q, TqlValidator as u, casePreservingForm as z, caseSensitiveSupport as V, formatValidationResult as F, getTqlIssues as U, isValidTqlSyntax as k, validateTql as v } from "./src/validator.js";
4
+ import { getCompletionTriggerCharacters as B, getCompletions as H, getWordAtPosition as D, shouldTriggerCompletion as W } from "./src/completionProvider.js";
5
+ import { findClosestMatch as w, fuzzyFilter as X, fuzzyMatch as b, highlightMatch as K, levenshteinDistance as Q } from "./src/fuzzyMatcher.js";
6
+ import { SchemaCache as j, createSchemaCache as J, getCachedField as $, getCachedFieldNames as ee, getCachedFieldType as te, getSchemaCache as re } from "./src/schemaCache.js";
7
+ import { ComplexityAnalyzer as oe, analyzeComplexity as Te, getComplexityMetrics as ae, getComplexityWarnings as Ee, isHighComplexity as le } from "./src/complexityAnalyzer.js";
8
+ import { SemanticPreview as Oe, flattenLogicTree as ne, formatLogicTreeAscii as se, formatLogicTreeNode as ge, generatePreview as Ae, getFieldUsage as me, getLogicTree as Re, getLogicTreeDepth as ce, getOperatorSummary as Ce, getUniqueFields as _e } from "./src/semanticPreview.js";
9
+ import { buildStatsQuery as Pe, parseVizHintString as de } from "./src/builder.js";
10
10
  export {
11
11
  r as AGGREGATION_FUNCTIONS,
12
12
  i as BOOLEAN_PREDICATE_MUTATORS,
13
13
  o as BOOLEAN_PREDICATE_MUTATOR_SET,
14
+ x as CASE_SENSITIVE_MEMBERSHIP_OPERATORS,
15
+ y as CASE_SENSITIVE_OPERATORS,
16
+ M as CASE_SENSITIVE_WHOLE_VALUE_OPERATORS,
14
17
  T as COLLECTION_OPERATORS,
15
18
  a as COMPARISON_OPERATORS,
16
- $ as ComplexityAnalyzer,
17
- l as KEYWORDS,
18
- n as LOGICAL_OPERATORS,
19
- I as MAX_REGEX_PATTERN_LENGTH,
20
- g as MUTATORS,
21
- s as NEGATION_SYMBOL_OPERATORS,
22
- O as SYMBOL_OPERATORS,
23
- X as SchemaCache,
24
- Te as SemanticPreview,
25
- m as TYPE_HINTS,
26
- h as TqlParser,
27
- A as TqlTokenizer,
28
- y as TqlValidator,
29
- c as VISUALIZATION_TYPES,
30
- ee as analyzeComplexity,
31
- Se as buildStatsQuery,
32
- b as createSchemaCache,
33
- B as findClosestMatch,
34
- E as findPreviousToken,
35
- S as findTokenAtPosition,
36
- p as findTokenBefore,
19
+ oe as ComplexityAnalyzer,
20
+ E as KEYWORDS,
21
+ l as LOGICAL_OPERATORS,
22
+ q as MAX_REGEX_PATTERN_LENGTH,
23
+ S as MUTATORS,
24
+ O as NEGATION_SYMBOL_OPERATORS,
25
+ n as SYMBOL_OPERATORS,
26
+ j as SchemaCache,
27
+ Oe as SemanticPreview,
28
+ s as TYPE_HINTS,
29
+ d as TqlParser,
30
+ g as TqlTokenizer,
31
+ u as TqlValidator,
32
+ A as VISUALIZATION_TYPES,
33
+ Te as analyzeComplexity,
34
+ Pe as buildStatsQuery,
35
+ z as casePreservingForm,
36
+ V as caseSensitiveSupport,
37
+ J as createSchemaCache,
38
+ w as findClosestMatch,
39
+ m as findPreviousToken,
40
+ R as findTokenAtPosition,
41
+ c as findTokenBefore,
37
42
  C as findTokensInRange,
38
- ae as flattenLogicTree,
39
- le as formatLogicTreeAscii,
40
- ne as formatLogicTreeNode,
41
- P as formatParseError,
42
- q as formatValidationResult,
43
- D as fuzzyFilter,
44
- Y as fuzzyMatch,
45
- ge as generatePreview,
46
- K as getCachedField,
47
- Q as getCachedFieldNames,
48
- Z as getCachedFieldType,
49
- F as getCompletionTriggerCharacters,
50
- G as getCompletions,
51
- te as getComplexityMetrics,
52
- re as getComplexityWarnings,
53
- se as getFieldUsage,
54
- Oe as getLogicTree,
55
- me as getLogicTreeDepth,
56
- Ae as getOperatorSummary,
57
- j as getSchemaCache,
58
- _ as getTqlErrors,
59
- M as getTqlIssues,
60
- ce as getUniqueFields,
61
- U as getWordAtPosition,
62
- H as highlightMatch,
63
- ie as isHighComplexity,
64
- N as isValidTql,
65
- u as isValidTqlSyntax,
66
- W as levenshteinDistance,
67
- x as parseTql,
68
- pe as parseVizHintString,
69
- V as shouldTriggerCompletion,
70
- d as tokenizeTql,
71
- f as tokenizeTqlNoWhitespace,
72
- z as validateTql
43
+ ne as flattenLogicTree,
44
+ se as formatLogicTreeAscii,
45
+ ge as formatLogicTreeNode,
46
+ f as formatParseError,
47
+ F as formatValidationResult,
48
+ X as fuzzyFilter,
49
+ b as fuzzyMatch,
50
+ Ae as generatePreview,
51
+ $ as getCachedField,
52
+ ee as getCachedFieldNames,
53
+ te as getCachedFieldType,
54
+ B as getCompletionTriggerCharacters,
55
+ H as getCompletions,
56
+ ae as getComplexityMetrics,
57
+ Ee as getComplexityWarnings,
58
+ me as getFieldUsage,
59
+ Re as getLogicTree,
60
+ ce as getLogicTreeDepth,
61
+ Ce as getOperatorSummary,
62
+ re as getSchemaCache,
63
+ h as getTqlErrors,
64
+ U as getTqlIssues,
65
+ _e as getUniqueFields,
66
+ D as getWordAtPosition,
67
+ K as highlightMatch,
68
+ le as isHighComplexity,
69
+ I as isValidTql,
70
+ k as isValidTqlSyntax,
71
+ Q as levenshteinDistance,
72
+ N as parseTql,
73
+ de as parseVizHintString,
74
+ W as shouldTriggerCompletion,
75
+ _ as tokenizeTql,
76
+ p as tokenizeTqlNoWhitespace,
77
+ v as validateTql
73
78
  };
@@ -6,10 +6,10 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- export type { TqlToken, TqlTokenType, TqlExpression, TqlBinaryExpression, TqlUnaryExpression, TqlComparisonExpression, TqlCollectionExpression, TqlMutatorExpression, TqlAggregationExpression, TqlStatsExpression, TqlGroupExpression, TqlLiteral, TqlFieldReference, TqlComparisonOperator, TqlLogicalOperator, TqlCollectionOperator, TqlMutator, TqlAggregationFunction, TqlTypeHint, TqlVisualizationType, TqlVizParams, TqlVizHint, TqlParseResult, TqlParseError, TqlParseWarning, TqlErrorCode, TqlWarningCode, TqlValidationResult, TqlValidationOptions, TqlFieldType, TqlCompletionItem, TqlCompletionKind, TqlCompletionContext, TqlCompletionOptions, TqlFieldSchema, TqlSnippet, TqlInputProps, TqlInputEmits, TqlInputExpose } from './types';
9
+ export type { TqlToken, TqlTokenType, TqlExpression, TqlBinaryExpression, TqlUnaryExpression, TqlComparisonExpression, TqlCollectionExpression, TqlMutatorExpression, TqlAggregationExpression, TqlStatsExpression, TqlGroupExpression, TqlLiteral, TqlFieldReference, TqlComparisonOperator, TqlLogicalOperator, TqlCollectionOperator, TqlMutator, TqlAggregationFunction, TqlTypeHint, TqlVisualizationType, TqlVizParams, TqlVizHint, TqlParseResult, TqlParseError, TqlParseWarning, TqlErrorCode, TqlWarningCode, TqlValidationResult, TqlValidationOptions, TqlFieldType, CaseSensitiveSupport, TqlCompletionItem, TqlCompletionKind, TqlCompletionContext, TqlCompletionOptions, TqlFieldSchema, TqlSnippet, TqlInputProps, TqlInputEmits, TqlInputExpose } from './types';
10
10
  export { TqlTokenizer, tokenizeTql, tokenizeTqlNoWhitespace, findTokenAtPosition, findTokensInRange, findTokenBefore, findPreviousToken, COMPARISON_OPERATORS, SYMBOL_OPERATORS, NEGATION_SYMBOL_OPERATORS, LOGICAL_OPERATORS, COLLECTION_OPERATORS, MUTATORS, BOOLEAN_PREDICATE_MUTATORS, BOOLEAN_PREDICATE_MUTATOR_SET, AGGREGATION_FUNCTIONS, TYPE_HINTS, VISUALIZATION_TYPES, KEYWORDS } from './tokenizer';
11
11
  export { TqlParser, parseTql, isValidTql, getTqlErrors, formatParseError } from './parser';
12
- export { TqlValidator, validateTql, isValidTqlSyntax, getTqlIssues, formatValidationResult, MAX_REGEX_PATTERN_LENGTH } from './validator';
12
+ export { TqlValidator, validateTql, isValidTqlSyntax, getTqlIssues, formatValidationResult, caseSensitiveSupport, casePreservingForm, CASE_SENSITIVE_OPERATORS, CASE_SENSITIVE_WHOLE_VALUE_OPERATORS, CASE_SENSITIVE_MEMBERSHIP_OPERATORS, MAX_REGEX_PATTERN_LENGTH } from './validator';
13
13
  export { getCompletions, getWordAtPosition, getCompletionTriggerCharacters, shouldTriggerCompletion } from './completionProvider';
14
14
  export { fuzzyMatch, levenshteinDistance, findClosestMatch, fuzzyFilter, highlightMatch, type FuzzyMatchResult, type FuzzyMatchOptions } from './fuzzyMatcher';
15
15
  export { SchemaCache, getSchemaCache, createSchemaCache, getCachedFieldNames, getCachedFieldType, getCachedField, type CachedSchema } from './schemaCache';
@@ -236,7 +236,39 @@ export type TqlWarningCode = "UNKNOWN_FIELD" | "TYPE_MISMATCH" | "DEPRECATED_OPE
236
236
  * refuse the query, because silently accepting it is the worse half of the same failure:
237
237
  * the user finds out at execution instead of at the keystroke.
238
238
  */
239
- | "ENGINE_DIVERGENCE";
239
+ | "ENGINE_DIVERGENCE"
240
+ /**
241
+ * The query parses, but the field cannot answer the operator and the query engine refuses
242
+ * it at execution.
243
+ *
244
+ * Raised for the `_cs` (case-sensitive) operators, under TWO rules rather than one --
245
+ * they do not share a predicate, and describing only the first is how this docstring was
246
+ * wrong on 90 of its own 98 firing cells before review:
247
+ *
248
+ * * the WHOLE-VALUE six (`contains_cs`, `startswith_cs`, `endswith_cs` + negations)
249
+ * whenever the field has no case-preserving form at all. That includes analyzed `text`
250
+ * with no `keyword` subfield AND every non-string type -- a `long`, `ip`, `date`,
251
+ * `boolean`, `geo_point`, `nested` or `object` field has no un-analyzed STRING form,
252
+ * and a substring match against one is not imprecise, it is unanswerable.
253
+ * * the MEMBERSHIP two (`in_cs`, `not_in_cs`) only when the base field is analyzed
254
+ * `text`. Case-sensitivity is vacuous for a number or an instant, and the query engine
255
+ * answers `in_cs` on those perfectly well.
256
+ *
257
+ * See `caseSensitiveSupport` in `src/validator.ts` for the predicate and for what the
258
+ * schema has to carry for this to fire at all.
259
+ *
260
+ * A WARNING and never an error, deliberately. The verdict is only as good as the schema
261
+ * the host supplied: a converter that flattens field names but drops multifields makes a
262
+ * perfectly translatable query look unanswerable, and a red squiggle over a query the
263
+ * cluster serves is the worse failure.
264
+ *
265
+ * Distinct from `TYPE_MISMATCH` because the objection is to the MAPPING, not the type --
266
+ * `text` is an accepted type for every `_cs` operator. The two can coincide on a
267
+ * non-string field, where the type is also wrong; the validator suppresses the softer
268
+ * `TYPE_MISMATCH` there rather than reporting both, so a consumer filtering by code sees
269
+ * one diagnostic per clause and the more accurate one.
270
+ */
271
+ | "UNANSWERABLE_MAPPING";
240
272
  export interface TqlValidationResult {
241
273
  valid: boolean;
242
274
  errors: TqlParseError[];
@@ -250,6 +282,16 @@ export interface TqlValidationOptions {
250
282
  allowMutators?: boolean;
251
283
  maxDepth?: number;
252
284
  }
285
+ /**
286
+ * Whether a field can answer a case-SENSITIVE (`_cs`) operator, as far as a supplied schema shows.
287
+ *
288
+ * Three-valued because the engines' rule keys on the index MAPPING while this package is
289
+ * handed a flat name→type map: `"unknown"` is a real and common answer, distinct from
290
+ * `"supported"`, and conflating the two is what let the editor green-light a query the
291
+ * engines refuse (tql#206). Produced by `caseSensitiveSupport` in `src/validator.ts`, which
292
+ * documents the predicate and its two blind spots.
293
+ */
294
+ export type CaseSensitiveSupport = "supported" | "unsupported" | "unknown";
253
295
  export type TqlFieldType = "text" | "keyword" | "long" | "integer" | "short" | "byte" | "double" | "float" | "half_float" | "scaled_float" | "unsigned_long" | "date" | "boolean" | "ip" | "nested" | "object" | "geo_point";
254
296
  export interface TqlCompletionItem {
255
297
  label: string;
@@ -346,6 +388,10 @@ export interface TqlInputEmits {
346
388
  * Reactive reference type for Vue computed properties.
347
389
  * This is a simplified type that matches Vue's ComputedRef interface
348
390
  * without requiring Vue as a direct dependency.
391
+ *
392
+ * @deprecated No longer used by `TqlInputExpose`: Vue unwraps refs on a
393
+ * component's exposed instance, so a template ref never saw a `.value` here.
394
+ * Kept exported so existing imports keep compiling.
349
395
  */
350
396
  export interface ReactiveRef<T> {
351
397
  readonly value: T;
@@ -359,12 +405,12 @@ export interface TqlInputExpose {
359
405
  getTokenAtPosition(pos: number): TqlToken | null;
360
406
  getCursorPosition(): number;
361
407
  setCursorPosition(pos: number): void;
362
- /** Whether the current query is valid (no syntax errors). Access via .value */
363
- isValid: ReactiveRef<boolean>;
364
- /** Whether the current query has validation errors. Access via .value */
365
- hasErrors: ReactiveRef<boolean>;
366
- /** Array of current validation errors. Access via .value */
367
- errors: ReactiveRef<TqlParseError[]>;
408
+ /** Whether the current query is valid (no syntax errors). */
409
+ readonly isValid: boolean;
410
+ /** Whether the current query has validation errors. */
411
+ readonly hasErrors: boolean;
412
+ /** Array of current validation errors. */
413
+ readonly errors: TqlParseError[];
368
414
  }
369
415
  export type ComplexityScore = "low" | "medium" | "high";
370
416
  export interface ComplexityWarning {
@@ -1,4 +1,4 @@
1
- import { TqlFieldType, TqlParseError, TqlParseWarning, TqlValidationOptions, TqlValidationResult } from './types';
1
+ import { CaseSensitiveSupport, TqlComparisonOperator, TqlFieldType, TqlParseError, TqlParseWarning, TqlValidationOptions, TqlValidationResult } from './types';
2
2
  /**
3
3
  * Maximum regex pattern length TQL will compile, in characters (code points).
4
4
  *
@@ -47,6 +47,140 @@ export declare const ORDERED_FIELD_TYPES: TqlFieldType[];
47
47
  * so this constant self-retires if Python ever adds it.
48
48
  */
49
49
  export declare const BETWEEN_FIELD_TYPES: TqlFieldType[];
50
+ /**
51
+ * The case-SENSITIVE WHOLE-VALUE operators: every spelling the `TqlComparisonOperator` type
52
+ * admits.
53
+ *
54
+ * TWELVE spellings across both families, EIGHT operators. The engines' constants — same two
55
+ * names, in `tql/src/opensearch/field_mappings.rs` and
56
+ * `src/tql/opensearch_components/field_mapping.py` — carry eight, because the engines only
57
+ * ever see `not_contains_cs`.
58
+ *
59
+ * The four `!` members are unreachable from `validate()`: `normalizeOperator` in
60
+ * `src/parser.ts` maps every `!x` through `NEGATION_SYMBOL_OPERATORS` before an AST exists,
61
+ * and `TqlValidator` takes a query string and nothing else. They are kept because this array
62
+ * is exported public API and a host may match raw user-typed text against it — pinned by "the
63
+ * `!` spellings reach the validator normalised", which also goes red if normalisation is ever
64
+ * removed and the `!` forms become live.
65
+ *
66
+ * `tests/caseSensitiveOperatorMapping.spec.ts` reads both engine constants and asserts these
67
+ * arrays cover exactly them, family by family, once the `!` forms are normalised — so the two
68
+ * cannot drift in either direction, and neither can the SPLIT between the families, which is
69
+ * the part that actually changes the predicate.
70
+ */
71
+ export declare const CASE_SENSITIVE_WHOLE_VALUE_OPERATORS: TqlComparisonOperator[];
72
+ /**
73
+ * The case-SENSITIVE MEMBERSHIP operators, kept separate for the reason the engines keep them
74
+ * separate: their refusal predicate is NARROWER.
75
+ *
76
+ * `in_cs` is a keyword operator (an exact-match `terms` query), so it routes through a
77
+ * different branch of `get_field_for_operator` (Python) / `get_query_field` (Rust), and that branch refuses
78
+ * only when the base field is analyzed `text`. The whole-value six refuse whenever there is
79
+ * no un-analyzed form at all. Folding the two lists into one is what made
80
+ * `caseSensitiveSupport` wrong for six operators in this PR's first round.
81
+ */
82
+ export declare const CASE_SENSITIVE_MEMBERSHIP_OPERATORS: TqlComparisonOperator[];
83
+ /** Every spelling of every case-SENSITIVE operator — the union of the two families above. */
84
+ export declare const CASE_SENSITIVE_OPERATORS: TqlComparisonOperator[];
85
+ /**
86
+ * Whether a field offers a CASE-PRESERVING form, as far as the supplied schema shows.
87
+ *
88
+ * This is the field half of the engines' rule, on its own because the two `_cs` operator
89
+ * families consume it differently (see `caseSensitiveSupport`, which is the function you
90
+ * probably want).
91
+ *
92
+ * * `"present"` — the field itself is `keyword`, or it has a `keyword` subfield. One whole
93
+ * value, one indexed term, case intact.
94
+ * * `"absent"` — no such form. That covers analyzed `text` with no `keyword` sibling AND
95
+ * every non-string type: a `long`, `ip`, `date` or `boolean` field has no un-analyzed
96
+ * STRING form either. Whether that matters depends on the operator, which is why this
97
+ * function does not decide it.
98
+ * * `"unknown"` — no `fieldTypes` was supplied, or this field is not in it.
99
+ *
100
+ * Mirrors `FieldMappings::unanalyzed_form` (Rust) and `FieldMapping.unanalyzed_field`
101
+ * (Python) as closely as a flat name→type map allows. Two documented divergences, both of
102
+ * which fail quiet — see `caseSensitiveSupport`.
103
+ *
104
+ * ## The sibling test is on TYPE, not on the name `.keyword`
105
+ *
106
+ * Both engines scan a field's declared subfields for one whose TYPE is `keyword` (Rust:
107
+ * `subfield_of(field, |t| *t == FieldType::Keyword)`; Python: `keyword_field`, set for any
108
+ * subfield with `"type": "keyword"`). A multifield named `.raw` or `.kw` answers exactly as
109
+ * well as one named `.keyword`, and hard-coding the name would report `"absent"` on a working
110
+ * mapping. So this walks the map for `${field}.` prefixed entries and looks at their type.
111
+ *
112
+ * ## One level down, matching the engines
113
+ *
114
+ * A subfield is a DIRECT child: both engines read a declared `subfields` map, so
115
+ * `f.sub.deep` is not a subfield of `f` to either of them. Scanning descendants at any depth
116
+ * would report `"present"` for a mapping the engines refuse.
117
+ */
118
+ export declare function casePreservingForm(field: string, fieldTypes?: Record<string, TqlFieldType>): "present" | "absent" | "unknown";
119
+ /**
120
+ * Whether a field can answer a case-SENSITIVE operator, as far as the supplied schema shows.
121
+ *
122
+ * Three-valued on purpose. The engines' rule keys on the MAPPING and this package is handed a
123
+ * flat name→type map, so there are genuinely three answers and collapsing them to two is how
124
+ * this ended up unimplemented for a release (tql#206):
125
+ *
126
+ * * `"unsupported"` — both engines raise (`TQLTypeError` / `OpenSearchError::TypeError`)
127
+ * for this field-and-operator pair. That is now true of every type, which it was not
128
+ * when this check was written: Rust's `parse_field_type` had no arm for `geo_point` or
129
+ * `unsigned_long`, dropped such a field from its mappings, and permitted the query —
130
+ * emitting a `wildcard` that could never match. Fixed in tql#210, in this same PR, and
131
+ * `no_field_type_is_silently_dropped` in
132
+ * `tql/tests/opensearch_case_sensitive_unanswerable.rs` holds the property for type
133
+ * names neither engine lists, not just for the two that were noticed.
134
+ * * `"supported"` — the schema shows nothing that would stop the engines translating it.
135
+ * * `"unknown"` — no `fieldTypes` was supplied, or this field is not in it. Nothing is
136
+ * claimed and no diagnostic should be produced.
137
+ *
138
+ * ## Why the OPERATOR is a parameter and not an afterthought
139
+ *
140
+ * The two `_cs` families do NOT share a predicate, and a field-only version of this function
141
+ * got it wrong for six of the eight operators before review caught it:
142
+ *
143
+ * * **Whole-value** (`contains_cs`, `startswith_cs`, `endswith_cs` + negations) refuse
144
+ * whenever there is no un-analyzed form at all — `field_mapping.py`'s
145
+ * `if self.unanalyzed_field is None and operator in CASE_SENSITIVE_WHOLE_VALUE_OPERATORS`,
146
+ * and the unconditional `if CASE_SENSITIVE_WHOLE_VALUE_OPERATORS.contains(&operator)` in
147
+ * `field_mappings.rs`. Neither is gated on the base type. Measured against the Python
148
+ * engine at `{"f": {"type": t}}`: `contains_cs`, `startswith_cs` and `endswith_cs` all
149
+ * raise for `long`, `ip`, `date` and `boolean`.
150
+ * * **Membership** (`in_cs`, `not_in_cs`) refuse only when the base field is analyzed
151
+ * `text` — `operator in CASE_SENSITIVE_MEMBERSHIP_OPERATORS and
152
+ * self.field_types.get(self.base_field_name) == "text"`, and its Rust twin. The same
153
+ * measurement: `f in_cs ['a']` translates to `{"terms": …}` for all four of those types,
154
+ * because case-sensitivity is vacuous for a number, an address, an instant or a flag.
155
+ *
156
+ * So "no case-preserving form" is the whole answer for six operators and half of it for two.
157
+ * `test_a_non_text_field_without_a_keyword_form_is_not_caught` pins the membership half only;
158
+ * reading its NAME as covering all eight is exactly how the field-only version passed review
159
+ * of its own tests.
160
+ *
161
+ * ## Two blind spots, both of which fail SILENT rather than loud
162
+ *
163
+ * 1. **A `wildcard` sibling reads as absent.** The engines accept `wildcard` as a
164
+ * case-preserving form (`FieldType::is_unanalyzed_string`), but `wildcard` is not a member
165
+ * of `TqlFieldType`, so a host cannot express it and this cannot see it.
166
+ * 2. **An object CHILD is indistinguishable from a multifield.** `os` (`text`) beside
167
+ * `os.name` (`keyword`) is read as case-preserving though `os.name` is a sibling field,
168
+ * not a subfield of `os`. A flat map carries no way to tell them apart.
169
+ *
170
+ * Blind spot 2 under-reports (a real refusal goes unwarned — no worse than before this
171
+ * existed), and blind spot 1 over-reports, which is the whole reason the caller emits a
172
+ * WARNING and not an error. Neither justifies staying silent in the ordinary ECS case, which
173
+ * is the case this answers.
174
+ *
175
+ * @param field - the field name as written in the query
176
+ * @param operator - the `_cs` operator being applied. A non-`_cs` operator always returns
177
+ * `"supported"`: this function answers one rule and does not stand in for the type tables.
178
+ * @param fieldTypes - the flat schema, exactly as passed in `TqlValidationOptions.fieldTypes`.
179
+ * For this to return anything but `"unknown"` it must contain the field; for it to
180
+ * distinguish the two `text` shapes it must ALSO contain the multifield entries
181
+ * (`message.keyword`), which is what an index-mapping flattener naturally produces.
182
+ */
183
+ export declare function caseSensitiveSupport(field: string, operator: TqlComparisonOperator, fieldTypes?: Record<string, TqlFieldType>): CaseSensitiveSupport;
50
184
  export declare class TqlValidator {
51
185
  private options;
52
186
  private errors;