@dorsk/tsumikit 0.9.0 → 0.9.2
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/schema.d.ts +12 -1
- package/dist/query/schema.js +8 -1
- package/dist/query/suggest.d.ts +7 -1
- package/dist/query/suggest.js +41 -6
- package/package.json +1 -1
package/dist/query/schema.d.ts
CHANGED
|
@@ -32,13 +32,24 @@ export interface FieldDef {
|
|
|
32
32
|
/** Static options, or omit and supply `provider` for async lookups. */
|
|
33
33
|
options?: ValueOption[];
|
|
34
34
|
provider?: ValueProvider;
|
|
35
|
+
/**
|
|
36
|
+
* Restrict the operators offered for this field to exactly this set (in
|
|
37
|
+
* catalogue order). When omitted, all operators legal for the field's `type`
|
|
38
|
+
* are offered. Use this to mirror a backend registry's per-field whitelist so
|
|
39
|
+
* the dropdown — and the parser's legal-op check — match what the server
|
|
40
|
+
* actually accepts.
|
|
41
|
+
*/
|
|
42
|
+
operators?: OperatorId[];
|
|
35
43
|
/** Placeholder shown in the value step of the dropdown. */
|
|
36
44
|
valuePlaceholder?: string;
|
|
37
45
|
}
|
|
38
46
|
export interface Schema {
|
|
39
47
|
fields: FieldDef[];
|
|
40
48
|
}
|
|
41
|
-
/** Operators legal for a given field, in catalogue order.
|
|
49
|
+
/** Operators legal for a given field, in catalogue order. When the field
|
|
50
|
+
* declares an explicit `operators` whitelist that takes precedence over the
|
|
51
|
+
* type-derived set (the whitelist is authoritative); otherwise every operator
|
|
52
|
+
* legal for the field's `type` is returned. */
|
|
42
53
|
export declare function operatorsFor(field: FieldDef): Operator[];
|
|
43
54
|
/** The default operator picked when a user selects a field (YouTrack-like). */
|
|
44
55
|
export declare function defaultOperator(field: FieldDef): Operator;
|
package/dist/query/schema.js
CHANGED
|
@@ -19,8 +19,15 @@ export const OPERATORS = [
|
|
|
19
19
|
{ id: 'in', label: 'any of', code: 'in', types: ['enum', 'id'], arity: 'many' },
|
|
20
20
|
{ id: 'range', label: 'in range', code: '..', types: ['date', 'number'], arity: 'two' },
|
|
21
21
|
];
|
|
22
|
-
/** Operators legal for a given field, in catalogue order.
|
|
22
|
+
/** Operators legal for a given field, in catalogue order. When the field
|
|
23
|
+
* declares an explicit `operators` whitelist that takes precedence over the
|
|
24
|
+
* type-derived set (the whitelist is authoritative); otherwise every operator
|
|
25
|
+
* legal for the field's `type` is returned. */
|
|
23
26
|
export function operatorsFor(field) {
|
|
27
|
+
if (field.operators) {
|
|
28
|
+
const allow = new Set(field.operators);
|
|
29
|
+
return OPERATORS.filter((op) => allow.has(op.id));
|
|
30
|
+
}
|
|
24
31
|
return OPERATORS.filter((op) => op.types.includes(field.type));
|
|
25
32
|
}
|
|
26
33
|
/** The default operator picked when a user selects a field (YouTrack-like). */
|
package/dist/query/suggest.d.ts
CHANGED
|
@@ -20,7 +20,13 @@ export interface SuggestState {
|
|
|
20
20
|
span: [number, number];
|
|
21
21
|
items: Suggestion[];
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* The token under the caret. Whitespace ends a token EXCEPT inside an open
|
|
25
|
+
* quote, so a quoted value containing spaces (`album:"ok computer`) stays one
|
|
26
|
+
* token and keeps the caret in the value step rather than collapsing to an
|
|
27
|
+
* empty token (which would wrongly re-offer fields). A closed quote followed by
|
|
28
|
+
* whitespace starts a fresh token (so the next `field:` can be chained).
|
|
29
|
+
*/
|
|
24
30
|
export declare function activeToken(s: string, pos: number): {
|
|
25
31
|
start: number;
|
|
26
32
|
end: number;
|
package/dist/query/suggest.js
CHANGED
|
@@ -9,14 +9,49 @@
|
|
|
9
9
|
import { findField, operatorsFor, resolveValues, } from './schema';
|
|
10
10
|
// Longest first so `>=`/`!:` win over `>`/`:`.
|
|
11
11
|
const OP_CODES = ['!:', '!=', '>=', '<=', ':', '=', '>', '<'];
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* The token under the caret. Whitespace ends a token EXCEPT inside an open
|
|
14
|
+
* quote, so a quoted value containing spaces (`album:"ok computer`) stays one
|
|
15
|
+
* token and keeps the caret in the value step rather than collapsing to an
|
|
16
|
+
* empty token (which would wrongly re-offer fields). A closed quote followed by
|
|
17
|
+
* whitespace starts a fresh token (so the next `field:` can be chained).
|
|
18
|
+
*/
|
|
13
19
|
export function activeToken(s, pos) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
// Walk from the start so we can track quote state; the last unquoted
|
|
21
|
+
// whitespace before the caret is the token boundary.
|
|
22
|
+
let start = 0;
|
|
23
|
+
let inQuote = false;
|
|
24
|
+
let q = '';
|
|
25
|
+
for (let i = 0; i < pos; i++) {
|
|
26
|
+
const c = s[i];
|
|
27
|
+
if (inQuote) {
|
|
28
|
+
if (c === q)
|
|
29
|
+
inQuote = false;
|
|
30
|
+
}
|
|
31
|
+
else if (c === '"' || c === "'") {
|
|
32
|
+
inQuote = true;
|
|
33
|
+
q = c;
|
|
34
|
+
}
|
|
35
|
+
else if (/\s/.test(c)) {
|
|
36
|
+
start = i + 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Extend forward through the rest of the token, still respecting quotes.
|
|
17
40
|
let end = pos;
|
|
18
|
-
|
|
19
|
-
|
|
41
|
+
for (let i = pos; i < s.length; i++) {
|
|
42
|
+
const c = s[i];
|
|
43
|
+
if (!inQuote && /\s/.test(c))
|
|
44
|
+
break;
|
|
45
|
+
if (inQuote) {
|
|
46
|
+
if (c === q)
|
|
47
|
+
inQuote = false;
|
|
48
|
+
}
|
|
49
|
+
else if (c === '"' || c === "'") {
|
|
50
|
+
inQuote = true;
|
|
51
|
+
q = c;
|
|
52
|
+
}
|
|
53
|
+
end = i + 1;
|
|
54
|
+
}
|
|
20
55
|
return { start, end, raw: s.slice(start, end) };
|
|
21
56
|
}
|
|
22
57
|
/** Split a token into field / operator-code / value parts (earliest op wins). */
|
package/package.json
CHANGED