@1771technologies/lytenyte-pro 2.0.4-dev.3 → 2.1.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/README.md +54 -11
- package/css/components/expression-editor.css +106 -0
- package/dist/components/column-manager/column-manager.d.ts +6 -1
- package/dist/components/column-manager/column-manager.js +23 -2
- package/dist/components/expressions-editor/create-completion-provider.d.ts +10 -0
- package/dist/components/expressions-editor/create-completion-provider.js +391 -0
- package/dist/components/expressions-editor/create-key-down-handler.d.ts +18 -0
- package/dist/components/expressions-editor/create-key-down-handler.js +49 -0
- package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.d.ts +2 -0
- package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.js +56 -0
- package/dist/components/expressions-editor/cursor-position/use-cursor-position.d.ts +5 -0
- package/dist/components/expressions-editor/cursor-position/use-cursor-position.js +33 -0
- package/dist/components/expressions-editor/expression-editor.d.ts +3 -0
- package/dist/components/expressions-editor/expression-editor.js +158 -0
- package/dist/components/expressions-editor/get-indentation.d.ts +1 -0
- package/dist/components/expressions-editor/get-indentation.js +7 -0
- package/dist/components/expressions-editor/handle-completion-key-down.d.ts +2 -0
- package/dist/components/expressions-editor/handle-completion-key-down.js +22 -0
- package/dist/components/expressions-editor/handle-enter-key.d.ts +4 -0
- package/dist/components/expressions-editor/handle-enter-key.js +11 -0
- package/dist/components/expressions-editor/handle-manual-trigger.d.ts +2 -0
- package/dist/components/expressions-editor/handle-manual-trigger.js +3 -0
- package/dist/components/expressions-editor/index.d.ts +18 -0
- package/dist/components/expressions-editor/index.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-context.d.ts +17 -0
- package/dist/components/expressions-editor/intellisence/completion-context.js +7 -0
- package/dist/components/expressions-editor/intellisence/completion-item.d.ts +5 -0
- package/dist/components/expressions-editor/intellisence/completion-item.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-list.d.ts +8 -0
- package/dist/components/expressions-editor/intellisence/completion-list.js +18 -0
- package/dist/components/expressions-editor/intellisence/completion-popover.d.ts +1 -0
- package/dist/components/expressions-editor/intellisence/completion-popover.js +47 -0
- package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.d.ts +2 -0
- package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.js +6 -0
- package/dist/components/expressions-editor/intellisence/get-word-at-cursor.d.ts +2 -0
- package/dist/components/expressions-editor/intellisence/get-word-at-cursor.js +12 -0
- package/dist/components/expressions-editor/intellisence/use-complete-trigger.d.ts +13 -0
- package/dist/components/expressions-editor/intellisence/use-complete-trigger.js +41 -0
- package/dist/components/expressions-editor/intellisence/use-completions.d.ts +14 -0
- package/dist/components/expressions-editor/intellisence/use-completions.js +78 -0
- package/dist/components/expressions-editor/replace-word-at-cursor.d.ts +5 -0
- package/dist/components/expressions-editor/replace-word-at-cursor.js +7 -0
- package/dist/components/expressions-editor/token-highlighter-default.d.ts +4 -0
- package/dist/components/expressions-editor/token-highlighter-default.js +20 -0
- package/dist/components/expressions-editor/types.d.ts +48 -0
- package/dist/components/expressions-editor/types.js +1 -0
- package/dist/components/expressions-editor/use-keyboard-navigation.d.ts +10 -0
- package/dist/components/expressions-editor/use-keyboard-navigation.js +37 -0
- package/dist/components/pill-manager/container.js +55 -9
- package/dist/components/pill-manager/item.js +15 -1
- package/dist/components/select-all.js +1 -1
- package/dist/components/tree-view/root.d.ts +9 -0
- package/dist/components/tree-view/root.js +4 -2
- package/dist/data-source-client/hooks/use-flattened-groups.js +2 -2
- package/dist/expressions/compiler/compile.d.ts +3 -0
- package/dist/expressions/compiler/compile.js +4 -0
- package/dist/expressions/compiler/eval-constant.d.ts +2 -0
- package/dist/expressions/compiler/eval-constant.js +19 -0
- package/dist/expressions/compiler/is-constant.d.ts +2 -0
- package/dist/expressions/compiler/is-constant.js +6 -0
- package/dist/expressions/compiler/make-constant.d.ts +2 -0
- package/dist/expressions/compiler/make-constant.js +11 -0
- package/dist/expressions/compiler/optimize.d.ts +3 -0
- package/dist/expressions/compiler/optimize.js +47 -0
- package/dist/expressions/compiler/value-of.d.ts +2 -0
- package/dist/expressions/compiler/value-of.js +11 -0
- package/dist/expressions/errors/clamp-offset.d.ts +1 -0
- package/dist/expressions/errors/clamp-offset.js +3 -0
- package/dist/expressions/errors/expression-error.d.ts +10 -0
- package/dist/expressions/errors/expression-error.js +19 -0
- package/dist/expressions/errors/format-error.d.ts +3 -0
- package/dist/expressions/errors/format-error.js +27 -0
- package/dist/expressions/errors/get-line-end.d.ts +1 -0
- package/dist/expressions/errors/get-line-end.js +8 -0
- package/dist/expressions/errors/get-line-start.d.ts +1 -0
- package/dist/expressions/errors/get-line-start.js +8 -0
- package/dist/expressions/errors/index.d.ts +7 -0
- package/dist/expressions/errors/index.js +6 -0
- package/dist/expressions/errors/offset-to-position.d.ts +2 -0
- package/dist/expressions/errors/offset-to-position.js +17 -0
- package/dist/expressions/errors/types.d.ts +10 -0
- package/dist/expressions/errors/types.js +1 -0
- package/dist/expressions/evaluator/evaluate-binary.d.ts +4 -0
- package/dist/expressions/evaluator/evaluate-binary.js +21 -0
- package/dist/expressions/evaluator/evaluate-unary.d.ts +2 -0
- package/dist/expressions/evaluator/evaluate-unary.js +10 -0
- package/dist/expressions/evaluator/evaluate.d.ts +15 -0
- package/dist/expressions/evaluator/evaluate.js +62 -0
- package/dist/expressions/index.d.ts +7 -0
- package/dist/expressions/index.js +5 -0
- package/dist/expressions/lexer/predicates/is-alpha-numeric.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-alpha-numeric.js +5 -0
- package/dist/expressions/lexer/predicates/is-alpha.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-alpha.js +3 -0
- package/dist/expressions/lexer/predicates/is-binary-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-binary-digit.js +3 -0
- package/dist/expressions/lexer/predicates/is-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-digit.js +3 -0
- package/dist/expressions/lexer/predicates/is-hex-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-hex-digit.js +4 -0
- package/dist/expressions/lexer/predicates/is-octal-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-octal-digit.js +3 -0
- package/dist/expressions/lexer/tokenize/consume-digits.d.ts +1 -0
- package/dist/expressions/lexer/tokenize/consume-digits.js +5 -0
- package/dist/expressions/lexer/tokenize/scan-identifier.d.ts +6 -0
- package/dist/expressions/lexer/tokenize/scan-identifier.js +20 -0
- package/dist/expressions/lexer/tokenize/scan-number.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-number.js +32 -0
- package/dist/expressions/lexer/tokenize/scan-operator.d.ts +6 -0
- package/dist/expressions/lexer/tokenize/scan-operator.js +71 -0
- package/dist/expressions/lexer/tokenize/scan-string-literal.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-string-literal.js +22 -0
- package/dist/expressions/lexer/tokenize/scan-string.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-string.js +98 -0
- package/dist/expressions/lexer/tokenize/scan-template-literal.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-template-literal.js +51 -0
- package/dist/expressions/lexer/tokenize/tokenize.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/tokenize.js +99 -0
- package/dist/expressions/lexer/types.d.ts +12 -0
- package/dist/expressions/lexer/types.js +1 -0
- package/dist/expressions/parser/parse-array-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-array-literal.js +15 -0
- package/dist/expressions/parser/parse-expression.d.ts +3 -0
- package/dist/expressions/parser/parse-expression.js +74 -0
- package/dist/expressions/parser/parse-object-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-object-literal.js +69 -0
- package/dist/expressions/parser/parse-pipe-transform.d.ts +3 -0
- package/dist/expressions/parser/parse-pipe-transform.js +26 -0
- package/dist/expressions/parser/parse-postfix.d.ts +3 -0
- package/dist/expressions/parser/parse-postfix.js +23 -0
- package/dist/expressions/parser/parse-primary.d.ts +3 -0
- package/dist/expressions/parser/parse-primary.js +35 -0
- package/dist/expressions/parser/parse-template-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-template-literal.js +41 -0
- package/dist/expressions/parser/parse-unary.d.ts +3 -0
- package/dist/expressions/parser/parse-unary.js +28 -0
- package/dist/expressions/parser/parse.d.ts +3 -0
- package/dist/expressions/parser/parse.js +26 -0
- package/dist/expressions/parser/parser-context.d.ts +12 -0
- package/dist/expressions/parser/parser-context.js +14 -0
- package/dist/expressions/parser/precedence.d.ts +1 -0
- package/dist/expressions/parser/precedence.js +8 -0
- package/dist/expressions/parser/types.d.ts +101 -0
- package/dist/expressions/parser/types.js +1 -0
- package/dist/expressions/plugin.d.ts +20 -0
- package/dist/expressions/plugin.js +1 -0
- package/dist/expressions/plugins/access.d.ts +2 -0
- package/dist/expressions/plugins/access.js +138 -0
- package/dist/expressions/plugins/arrows.d.ts +2 -0
- package/dist/expressions/plugins/arrows.js +83 -0
- package/dist/expressions/plugins/booleans.d.ts +2 -0
- package/dist/expressions/plugins/booleans.js +34 -0
- package/dist/expressions/plugins/collections.d.ts +2 -0
- package/dist/expressions/plugins/collections.js +70 -0
- package/dist/expressions/plugins/comparison.d.ts +2 -0
- package/dist/expressions/plugins/comparison.js +51 -0
- package/dist/expressions/plugins/date-identifier.d.ts +4 -0
- package/dist/expressions/plugins/date-identifier.js +29 -0
- package/dist/expressions/plugins/date-literal.d.ts +2 -0
- package/dist/expressions/plugins/date-literal.js +71 -0
- package/dist/expressions/plugins/logical.d.ts +2 -0
- package/dist/expressions/plugins/logical.js +103 -0
- package/dist/expressions/plugins/membership.d.ts +2 -0
- package/dist/expressions/plugins/membership.js +71 -0
- package/dist/expressions/plugins/pipe.d.ts +2 -0
- package/dist/expressions/plugins/pipe.js +57 -0
- package/dist/expressions/plugins/quoted-identifier.d.ts +2 -0
- package/dist/expressions/plugins/quoted-identifier.js +35 -0
- package/dist/expressions/plugins/resolved-identifier.d.ts +5 -0
- package/dist/expressions/plugins/resolved-identifier.js +19 -0
- package/dist/expressions/plugins/standard.d.ts +15 -0
- package/dist/expressions/plugins/standard.js +27 -0
- package/dist/expressions/plugins/strings.d.ts +2 -0
- package/dist/expressions/plugins/strings.js +44 -0
- package/dist/expressions/plugins/ternary.d.ts +2 -0
- package/dist/expressions/plugins/ternary.js +58 -0
- package/dist/expressions.d.ts +2 -0
- package/dist/expressions.js +2 -0
- package/dist/index.d.ts +1 -0
- package/package.json +12 -5
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ to **LyteNyte Grid PRO** for advanced enterprise features and support.
|
|
|
35
35
|
[](https://www.npmjs.com/package/@1771technologies/lytenyte-core)
|
|
36
36
|
[](https://github.com/1771-Technologies/lytenyte/tree/main)
|
|
37
37
|
[](https://github.com/1771-Technologies/lytenyte)
|
|
38
|
-
[](
|
|
38
|
+
[](https://github.com/1771-Technologies/lytenyte/blob/main/CODE_OF_CONDUCT.md)
|
|
39
39
|
[](https://github.com/1771-Technologies/lytenyte/actions/workflows/release.yml?query=branch%3Amain)
|
|
40
40
|
[](https://x.com/1771tech)
|
|
41
41
|
[](https://www.linkedin.com/company/1771technologies)
|
|
@@ -55,14 +55,34 @@ to **LyteNyte Grid PRO** for advanced enterprise features and support.
|
|
|
55
55
|
|
|
56
56
|
LyteNyte Grid is available in two editions:
|
|
57
57
|
|
|
58
|
-
1. **LyteNyte Grid Core
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
1. **LyteNyte Grid Core:** Free, **open-source edition** for building high-performance data tables. Includes sorting,
|
|
59
|
+
filtering, editing, row selection, detail views, and more. Also includes advanced features such
|
|
60
|
+
as aggregation, row grouping, and cell range selection, often locked behind paywalls in other grids.
|
|
61
61
|
|
|
62
|
-
2. **LyteNyte Grid PRO: Commercial edition** that extends Core with powerful enterprise
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
2. **LyteNyte Grid PRO: Commercial edition** that extends Core with powerful enterprise features,
|
|
63
|
+
including server-side data loading, pivoting, tree data, component managers, and advanced
|
|
64
|
+
filtering. Build custom menus, popovers, expressions, and workflow-driven UIs with ease.
|
|
65
|
+
|
|
66
|
+
## AI-Enhanced Workflows
|
|
67
|
+
|
|
68
|
+
**LyteNyte Grid AI Skills** are structured context files for Claude Code, Windsurf, Cursor, and other AI coding agents.
|
|
69
|
+
Skills provide agents with accurate, curated context for LyteNyte Grid, allowing them to generate complex
|
|
70
|
+
grid implementations with greater speed and reliability.
|
|
71
|
+
|
|
72
|
+
Instead of building the grid manually, developers can describe the
|
|
73
|
+
desired result and let the agent generate the implementation.
|
|
74
|
+
|
|
75
|
+
**Install LyteNyte Grid AI Skills**
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx skills add 1771-Technologies/lytenyte
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Once installed, the Skill activates automatically whenever you work on a LyteNyte Grid task. No
|
|
82
|
+
special prompting is needed. Skills are actively maintained by the 1771 Technologies
|
|
83
|
+
team and versioned alongside each LyteNyte Grid release.
|
|
84
|
+
|
|
85
|
+
See our [AI Skills Overview guide](https://1771technologies.com/docs/ai-skills-overview) to learn more.
|
|
66
86
|
|
|
67
87
|
## Features
|
|
68
88
|
|
|
@@ -79,6 +99,16 @@ LyteNyte Grid is available in two editions:
|
|
|
79
99
|
|
|
80
100
|
</details>
|
|
81
101
|
|
|
102
|
+
<details>
|
|
103
|
+
<summary><b>🤖 AI Enhanced Workflows</b></summary>
|
|
104
|
+
<br>
|
|
105
|
+
|
|
106
|
+
| Feature | Core | PRO |
|
|
107
|
+
| --------------------------------------------------------------------- | :--: | :-: |
|
|
108
|
+
| [AI Skills](https://www.1771technologies.com/docs/ai-skills-overview) | ✅ | ✅ |
|
|
109
|
+
|
|
110
|
+
</details>
|
|
111
|
+
|
|
82
112
|
<details>
|
|
83
113
|
<summary><b>🔌 API Extensions</b></summary>
|
|
84
114
|
<br>
|
|
@@ -198,8 +228,8 @@ LyteNyte Grid is available in two editions:
|
|
|
198
228
|
| ↳ [Checkbox Row Selection](https://www.1771technologies.com/docs/row-selection#checkbox-selection) | ✅ | ✅ |
|
|
199
229
|
| ↳ [Isolated Row Selection](https://www.1771technologies.com/docs/row-selection#isolated-row-selection) | ✅ | ✅ |
|
|
200
230
|
| ↳ [Linked Row Selection](https://www.1771technologies.com/docs/row-selection#linked-row-selection) | ✅ | ✅ |
|
|
201
|
-
| [Cell Selection](https://www.1771technologies.com/docs/cell-selection#single-range-selection) |
|
|
202
|
-
| [Cell Range Selection](https://www.1771technologies.com/docs/cell-selection#multi-range-selection) |
|
|
231
|
+
| [Cell Selection](https://www.1771technologies.com/docs/cell-selection#single-range-selection) | ✅ | ✅ |
|
|
232
|
+
| [Cell Range Selection](https://www.1771technologies.com/docs/cell-selection#multi-range-selection) | ✅ | ✅ |
|
|
203
233
|
|
|
204
234
|
</details>
|
|
205
235
|
|
|
@@ -239,6 +269,19 @@ LyteNyte Grid is available in two editions:
|
|
|
239
269
|
|
|
240
270
|
</details>
|
|
241
271
|
|
|
272
|
+
<details>
|
|
273
|
+
<summary><b>🧮 Expressions</b> </summary>
|
|
274
|
+
<br>
|
|
275
|
+
|
|
276
|
+
| Feature | Core | PRO |
|
|
277
|
+
| -------------------------------------------------------------------------------- | :--: | :-: |
|
|
278
|
+
| [Expressions Engine](https://www.1771technologies.com/docs/expressions-overview) | — | ✅ |
|
|
279
|
+
| [Filter Expressions](https://www.1771technologies.com/docs/expression-filters) | — | ✅ |
|
|
280
|
+
| [Expression Editor](https://www.1771technologies.com/docs/expression-editor) | — | ✅ |
|
|
281
|
+
| [Expression Plugins](https://www.1771technologies.com/docs/expression-plugins) | — | ✅ |
|
|
282
|
+
|
|
283
|
+
</details>
|
|
284
|
+
|
|
242
285
|
<details>
|
|
243
286
|
<summary><b>📦 Grouping & Aggregations</b></summary>
|
|
244
287
|
<br>
|
|
@@ -377,7 +420,7 @@ npm install --save @1771technologies/lytenyte-pro
|
|
|
377
420
|
|
|
378
421
|
> [!NOTE]
|
|
379
422
|
> You can install and use LyteNyte Grid PRO
|
|
380
|
-
> without license but a watermark will be displayed.
|
|
423
|
+
> without a license, but a watermark will be displayed.
|
|
381
424
|
|
|
382
425
|
**Core:**
|
|
383
426
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
@layer ln-grid {
|
|
2
|
+
[data-ln-expression-editor] {
|
|
3
|
+
--ln-expr-number: light-dark(#b45309, #fab387);
|
|
4
|
+
--ln-expr-string: light-dark(#15803d, #a6e3a1);
|
|
5
|
+
--ln-expr-date: light-dark(#0e7490, #89dceb);
|
|
6
|
+
--ln-expr-keyword: light-dark(#7c3aed, #cba6f7);
|
|
7
|
+
--ln-expr-identifier: light-dark(#0369a1, #89b4fa);
|
|
8
|
+
--ln-expr-operator: light-dark(#be185d, #f38ba8);
|
|
9
|
+
--ln-expr-punctuation: light-dark(#6b7280, #6c7086);
|
|
10
|
+
--ln-expr-error: light-dark(#dc2626, #f38ba8);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* These must be identical otherwise the highlight will not match the input. */
|
|
14
|
+
[data-ln-expression-editor] {
|
|
15
|
+
font-family:
|
|
16
|
+
ui-monospace, "Cascadia Code", "Segoe UI Mono", "Liberation Mono", Menlo, Monaco, Consolas, monospace;
|
|
17
|
+
font-size: var(--ln-font-sm);
|
|
18
|
+
white-space: nowrap;
|
|
19
|
+
word-break: normal;
|
|
20
|
+
overflow-wrap: normal;
|
|
21
|
+
tab-size: 2;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
[data-ln-expression-input] {
|
|
26
|
+
caret-color: var(--ln-text);
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
|
|
29
|
+
transition-property: border-color;
|
|
30
|
+
transition-duration: var(--ln-transition-duration);
|
|
31
|
+
transition-timing-function: var(--ln-transition-fn);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Completion popover */
|
|
35
|
+
@keyframes ln-expr-popover-in {
|
|
36
|
+
from {
|
|
37
|
+
opacity: 0;
|
|
38
|
+
translate: 0 -4px;
|
|
39
|
+
}
|
|
40
|
+
to {
|
|
41
|
+
opacity: 1;
|
|
42
|
+
translate: 0 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[data-ln-expression-popover] {
|
|
47
|
+
background-color: var(--ln-bg-popover);
|
|
48
|
+
border: 1px solid var(--ln-border-popover);
|
|
49
|
+
border-radius: var(--ln-radius-md);
|
|
50
|
+
box-shadow: var(--ln-shadow-400);
|
|
51
|
+
padding: var(--ln-space-05);
|
|
52
|
+
min-width: 200px;
|
|
53
|
+
max-width: 360px;
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
|
|
57
|
+
&:popover-open {
|
|
58
|
+
animation: ln-expr-popover-in var(--ln-transition-duration) var(--ln-transition-fn) both;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[data-ln-expression-completion-list] {
|
|
63
|
+
list-style: none;
|
|
64
|
+
margin: 0;
|
|
65
|
+
padding: 0;
|
|
66
|
+
max-height: 220px;
|
|
67
|
+
overflow-y: auto;
|
|
68
|
+
overscroll-behavior: contain;
|
|
69
|
+
|
|
70
|
+
/* Thin scrollbar */
|
|
71
|
+
scrollbar-width: thin;
|
|
72
|
+
scrollbar-color: var(--ln-border-strong) transparent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
[data-ln-expression-completion-item] {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: var(--ln-space-10);
|
|
79
|
+
padding-block: var(--ln-space-05);
|
|
80
|
+
padding-inline: var(--ln-space-10);
|
|
81
|
+
border-radius: var(--ln-radius);
|
|
82
|
+
font-family:
|
|
83
|
+
ui-monospace, "Cascadia Code", "Segoe UI Mono", "Liberation Mono", Menlo, Monaco, Consolas, monospace;
|
|
84
|
+
font-size: var(--ln-font-sm);
|
|
85
|
+
color: var(--ln-text);
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
user-select: none;
|
|
88
|
+
|
|
89
|
+
transition-property: background-color, color;
|
|
90
|
+
transition-duration: var(--ln-transition-duration);
|
|
91
|
+
transition-timing-function: var(--ln-transition-fn);
|
|
92
|
+
|
|
93
|
+
&:hover {
|
|
94
|
+
background-color: var(--ln-bg-row-hover);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&[data-ln-selected] {
|
|
98
|
+
background-color: var(--ln-primary-10);
|
|
99
|
+
color: var(--ln-text-dark);
|
|
100
|
+
|
|
101
|
+
&:hover {
|
|
102
|
+
background-color: var(--ln-primary-10);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -9,5 +9,10 @@ export interface ColumnManagerProps<Spec extends GridSpec = GridSpec> {
|
|
|
9
9
|
columns: Column<Spec>[];
|
|
10
10
|
row: RowNode<Spec["data"]>;
|
|
11
11
|
}) => ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* @alpha
|
|
14
|
+
* Use with caution.
|
|
15
|
+
*/
|
|
16
|
+
readonly getPillManagerTag?: (column: Column<Spec>) => Record<string, string>;
|
|
12
17
|
}
|
|
13
|
-
export declare function ColumnManager<Spec extends GridSpec = GridSpec>({ columns: provided, base, onColumnsChange, endElement, }: ColumnManagerProps<Spec>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function ColumnManager<Spec extends GridSpec = GridSpec>({ columns: provided, base, onColumnsChange, endElement, getPillManagerTag, }: ColumnManagerProps<Spec>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,7 +3,7 @@ import { useMemo } from "react";
|
|
|
3
3
|
import { TreeView } from "../tree-view/index.js";
|
|
4
4
|
import { Checkbox } from "../checkbox/checkbox.js";
|
|
5
5
|
import { computePathMatrix } from "@1771technologies/lytenyte-shared";
|
|
6
|
-
export function ColumnManager({ columns: provided, base, onColumnsChange, endElement, }) {
|
|
6
|
+
export function ColumnManager({ columns: provided, base, onColumnsChange, endElement, getPillManagerTag, }) {
|
|
7
7
|
const nonAdjacentSplit = useMemo(() => {
|
|
8
8
|
const paths = computePathMatrix(provided);
|
|
9
9
|
const adjusted = [];
|
|
@@ -24,7 +24,28 @@ export function ColumnManager({ columns: provided, base, onColumnsChange, endEle
|
|
|
24
24
|
const items = useMemo(() => {
|
|
25
25
|
return nonAdjacentSplit.map((x) => ({ id: x.id, path: x.groupPath ?? [], name: x.name, column: x }));
|
|
26
26
|
}, [nonAdjacentSplit]);
|
|
27
|
-
|
|
27
|
+
const getDragItems = useMemo(() => {
|
|
28
|
+
if (!getPillManagerTag)
|
|
29
|
+
return undefined;
|
|
30
|
+
return (row, leafs) => {
|
|
31
|
+
if (leafs.length || row.kind !== "leaf")
|
|
32
|
+
return {};
|
|
33
|
+
const column = row.data.column;
|
|
34
|
+
const mapTags = Object.entries(getPillManagerTag(column));
|
|
35
|
+
if (!mapTags.length)
|
|
36
|
+
return {};
|
|
37
|
+
return {
|
|
38
|
+
pill: {
|
|
39
|
+
kind: "site",
|
|
40
|
+
data: {
|
|
41
|
+
id: "__external__",
|
|
42
|
+
item: Object.fromEntries(mapTags),
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
}, [getPillManagerTag]);
|
|
48
|
+
return (_jsx(TreeView, { items: items, rowSelectionEnabled: false, draggable: true, rowHeight: 30, rowSelectAllShow: false, getDragTags: getDragItems, defaultExpansion: true, onItemsReordered: (x) => {
|
|
28
49
|
const columns = x.map((x) => provided.find((p) => p.id === x.column.id));
|
|
29
50
|
onColumnsChange(columns);
|
|
30
51
|
}, children: ({ row, leafs, toggle, dragProps, isOver, isBefore }) => {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Token } from "../../expressions/lexer/types.js";
|
|
2
|
+
import type { CompletionItem } from "./types.js";
|
|
3
|
+
export type ContextEntry = {
|
|
4
|
+
value: unknown;
|
|
5
|
+
type: "string" | "number" | "array" | "object" | "function" | "boolean" | "date";
|
|
6
|
+
return?: "string" | "number" | "array" | "object" | "date";
|
|
7
|
+
};
|
|
8
|
+
type CompletionContext = Record<string, ContextEntry>;
|
|
9
|
+
export declare function createCompletionProvider(context: CompletionContext): (tokens: Token[], cursorPosition: number) => CompletionItem[];
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
const STRING_METHODS = [
|
|
2
|
+
{ label: "at", kind: "function" },
|
|
3
|
+
{ label: "charAt", kind: "function" },
|
|
4
|
+
{ label: "charCodeAt", kind: "function" },
|
|
5
|
+
{ label: "endsWith", kind: "function" },
|
|
6
|
+
{ label: "includes", kind: "function" },
|
|
7
|
+
{ label: "indexOf", kind: "function" },
|
|
8
|
+
{ label: "lastIndexOf", kind: "function" },
|
|
9
|
+
{ label: "length", kind: "number" },
|
|
10
|
+
{ label: "match", kind: "function" },
|
|
11
|
+
{ label: "padEnd", kind: "function" },
|
|
12
|
+
{ label: "padStart", kind: "function" },
|
|
13
|
+
{ label: "repeat", kind: "function" },
|
|
14
|
+
{ label: "replace", kind: "function" },
|
|
15
|
+
{ label: "replaceAll", kind: "function" },
|
|
16
|
+
{ label: "slice", kind: "function" },
|
|
17
|
+
{ label: "split", kind: "function" },
|
|
18
|
+
{ label: "startsWith", kind: "function" },
|
|
19
|
+
{ label: "substring", kind: "function" },
|
|
20
|
+
{ label: "toLowerCase", kind: "function" },
|
|
21
|
+
{ label: "toUpperCase", kind: "function" },
|
|
22
|
+
{ label: "trim", kind: "function" },
|
|
23
|
+
{ label: "trimEnd", kind: "function" },
|
|
24
|
+
{ label: "trimStart", kind: "function" },
|
|
25
|
+
];
|
|
26
|
+
const ARRAY_METHODS = [
|
|
27
|
+
{ label: "at", kind: "function" },
|
|
28
|
+
{ label: "concat", kind: "function" },
|
|
29
|
+
{ label: "entries", kind: "function" },
|
|
30
|
+
{ label: "every", kind: "function" },
|
|
31
|
+
{ label: "filter", kind: "function" },
|
|
32
|
+
{ label: "find", kind: "function" },
|
|
33
|
+
{ label: "findIndex", kind: "function" },
|
|
34
|
+
{ label: "flat", kind: "function" },
|
|
35
|
+
{ label: "flatMap", kind: "function" },
|
|
36
|
+
{ label: "forEach", kind: "function" },
|
|
37
|
+
{ label: "includes", kind: "function" },
|
|
38
|
+
{ label: "indexOf", kind: "function" },
|
|
39
|
+
{ label: "join", kind: "function" },
|
|
40
|
+
{ label: "keys", kind: "function" },
|
|
41
|
+
{ label: "length", kind: "number" },
|
|
42
|
+
{ label: "map", kind: "function" },
|
|
43
|
+
{ label: "reduce", kind: "function" },
|
|
44
|
+
{ label: "reduceRight", kind: "function" },
|
|
45
|
+
{ label: "reverse", kind: "function" },
|
|
46
|
+
{ label: "slice", kind: "function" },
|
|
47
|
+
{ label: "some", kind: "function" },
|
|
48
|
+
{ label: "sort", kind: "function" },
|
|
49
|
+
{ label: "values", kind: "function" },
|
|
50
|
+
];
|
|
51
|
+
const DATE_METHODS = [
|
|
52
|
+
{ label: "getTime", kind: "function" },
|
|
53
|
+
{ label: "toISOString", kind: "function" },
|
|
54
|
+
];
|
|
55
|
+
const NUMBER_METHODS = [
|
|
56
|
+
{ label: "toExponential", kind: "function" },
|
|
57
|
+
{ label: "toFixed", kind: "function" },
|
|
58
|
+
{ label: "toLocaleString", kind: "function" },
|
|
59
|
+
{ label: "toPrecision", kind: "function" },
|
|
60
|
+
{ label: "toString", kind: "function" },
|
|
61
|
+
{ label: "valueOf", kind: "function" },
|
|
62
|
+
];
|
|
63
|
+
function isDot(token) {
|
|
64
|
+
return (token.type === "Punctuation" && token.value === ".") || token.type === "OptionalChain";
|
|
65
|
+
}
|
|
66
|
+
function isClosingBracket(token) {
|
|
67
|
+
return token.type === "Punctuation" && token.value === "]";
|
|
68
|
+
}
|
|
69
|
+
function isCompleteValue(token) {
|
|
70
|
+
return (token.type === "Identifier" ||
|
|
71
|
+
token.type === "QuotedIdentifier" ||
|
|
72
|
+
token.type === "Number" ||
|
|
73
|
+
token.type === "String" ||
|
|
74
|
+
token.type === "TemplateLiteral" ||
|
|
75
|
+
(token.type === "Punctuation" && (token.value === ")" || token.value === "]")));
|
|
76
|
+
}
|
|
77
|
+
function isStringLiteral(token) {
|
|
78
|
+
return token.type === "String" || token.type === "TemplateLiteral";
|
|
79
|
+
}
|
|
80
|
+
const BINARY_OPERATORS = [
|
|
81
|
+
{ label: "+ Plus", kind: "operator", value: "+" },
|
|
82
|
+
{ label: "- Minus", kind: "operator", value: "-" },
|
|
83
|
+
{ label: "* Multiply", kind: "operator", value: "*" },
|
|
84
|
+
{ label: "/ Divide", kind: "operator", value: "/" },
|
|
85
|
+
{ label: "% Modulus", kind: "operator", value: "%" },
|
|
86
|
+
{ label: "** Exponentiation", kind: "operator", value: "**" },
|
|
87
|
+
{ label: "== Equal To", kind: "operator", value: "==" },
|
|
88
|
+
{ label: "!= Not Equal To", kind: "operator", value: "!=" },
|
|
89
|
+
{ label: "< Less Than", kind: "operator", value: "<" },
|
|
90
|
+
{ label: "<= Less Than Or Equal To", kind: "operator", value: "<=" },
|
|
91
|
+
{ label: "> Greater Than", kind: "operator", value: ">" },
|
|
92
|
+
{ label: ">= Greater Than Or Equal To", kind: "operator", value: ">=" },
|
|
93
|
+
{ label: "&& AND", kind: "operator", value: "&&" },
|
|
94
|
+
{ label: "|| OR", kind: "operator", value: "||" },
|
|
95
|
+
{ label: "?? OR if Null", kind: "operator", value: "??" },
|
|
96
|
+
{ label: "|> Pipe", kind: "operator", value: "|>" },
|
|
97
|
+
];
|
|
98
|
+
const STRING_METHOD_RETURNS = {
|
|
99
|
+
at: "string",
|
|
100
|
+
charAt: "string",
|
|
101
|
+
charCodeAt: "number",
|
|
102
|
+
endsWith: "unknown",
|
|
103
|
+
includes: "unknown",
|
|
104
|
+
indexOf: "number",
|
|
105
|
+
lastIndexOf: "number",
|
|
106
|
+
match: "array",
|
|
107
|
+
padEnd: "string",
|
|
108
|
+
padStart: "string",
|
|
109
|
+
repeat: "string",
|
|
110
|
+
replace: "string",
|
|
111
|
+
replaceAll: "string",
|
|
112
|
+
slice: "string",
|
|
113
|
+
split: "array",
|
|
114
|
+
startsWith: "unknown",
|
|
115
|
+
substring: "string",
|
|
116
|
+
toLowerCase: "string",
|
|
117
|
+
toUpperCase: "string",
|
|
118
|
+
trim: "string",
|
|
119
|
+
trimEnd: "string",
|
|
120
|
+
trimStart: "string",
|
|
121
|
+
};
|
|
122
|
+
const ARRAY_METHOD_RETURNS = {
|
|
123
|
+
at: "unknown",
|
|
124
|
+
concat: "array",
|
|
125
|
+
entries: "unknown",
|
|
126
|
+
every: "unknown",
|
|
127
|
+
filter: "array",
|
|
128
|
+
find: "unknown",
|
|
129
|
+
findIndex: "number",
|
|
130
|
+
flat: "array",
|
|
131
|
+
flatMap: "array",
|
|
132
|
+
forEach: "unknown",
|
|
133
|
+
includes: "unknown",
|
|
134
|
+
indexOf: "number",
|
|
135
|
+
join: "string",
|
|
136
|
+
keys: "unknown",
|
|
137
|
+
map: "array",
|
|
138
|
+
reduce: "unknown",
|
|
139
|
+
reduceRight: "unknown",
|
|
140
|
+
reverse: "array",
|
|
141
|
+
slice: "array",
|
|
142
|
+
some: "unknown",
|
|
143
|
+
sort: "array",
|
|
144
|
+
values: "unknown",
|
|
145
|
+
};
|
|
146
|
+
const DATE_METHOD_RETURNS = {
|
|
147
|
+
getTime: "number",
|
|
148
|
+
toISOString: "string",
|
|
149
|
+
};
|
|
150
|
+
function kindOf(value) {
|
|
151
|
+
if (typeof value === "function")
|
|
152
|
+
return "function";
|
|
153
|
+
if (Array.isArray(value))
|
|
154
|
+
return "array";
|
|
155
|
+
if (typeof value === "string")
|
|
156
|
+
return "string";
|
|
157
|
+
if (typeof value === "number")
|
|
158
|
+
return "number";
|
|
159
|
+
if (typeof value === "boolean")
|
|
160
|
+
return "boolean";
|
|
161
|
+
if (typeof value === "object" && value !== null)
|
|
162
|
+
return "object";
|
|
163
|
+
return "unknown";
|
|
164
|
+
}
|
|
165
|
+
function isContextEntry(v) {
|
|
166
|
+
return v != null && typeof v === "object" && "type" in v && "value" in v;
|
|
167
|
+
}
|
|
168
|
+
function resolveEntry(context, path) {
|
|
169
|
+
if (path.length === 0)
|
|
170
|
+
return undefined;
|
|
171
|
+
let entry = context[path[0]];
|
|
172
|
+
for (let i = 1; i < path.length; i++) {
|
|
173
|
+
if (!entry || entry.value == null || typeof entry.value !== "object")
|
|
174
|
+
return undefined;
|
|
175
|
+
const nested = entry.value[path[i]];
|
|
176
|
+
if (isContextEntry(nested)) {
|
|
177
|
+
entry = nested;
|
|
178
|
+
}
|
|
179
|
+
else if (nested !== undefined) {
|
|
180
|
+
entry = { value: nested, type: kindOf(nested) };
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return entry;
|
|
187
|
+
}
|
|
188
|
+
function findMatchingOpenParen(relevant, closeIndex) {
|
|
189
|
+
let depth = 1;
|
|
190
|
+
let i = closeIndex - 1;
|
|
191
|
+
while (i >= 0) {
|
|
192
|
+
if (relevant[i].type === "Punctuation") {
|
|
193
|
+
if (relevant[i].value === ")")
|
|
194
|
+
depth++;
|
|
195
|
+
else if (relevant[i].value === "(") {
|
|
196
|
+
if (--depth === 0)
|
|
197
|
+
return i;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
i--;
|
|
201
|
+
}
|
|
202
|
+
return -1;
|
|
203
|
+
}
|
|
204
|
+
function buildPathFromTokens(relevant, i) {
|
|
205
|
+
const tokenName = (t) => (t.type === "QuotedIdentifier" ? t.value.slice(2, -1) : t.value);
|
|
206
|
+
const token = relevant[i];
|
|
207
|
+
if (!token || (token.type !== "Identifier" && token.type !== "QuotedIdentifier"))
|
|
208
|
+
return null;
|
|
209
|
+
const path = [tokenName(token)];
|
|
210
|
+
let j = i - 1;
|
|
211
|
+
while (j >= 1 && isDot(relevant[j])) {
|
|
212
|
+
j--;
|
|
213
|
+
if (relevant[j].type !== "Identifier" && relevant[j].type !== "QuotedIdentifier")
|
|
214
|
+
break;
|
|
215
|
+
path.unshift(tokenName(relevant[j]));
|
|
216
|
+
j--;
|
|
217
|
+
}
|
|
218
|
+
return path;
|
|
219
|
+
}
|
|
220
|
+
function resolveTypeOf(relevant, i, context) {
|
|
221
|
+
const token = relevant[i];
|
|
222
|
+
if (!token)
|
|
223
|
+
return "unknown";
|
|
224
|
+
if (token.type === "DateLiteral")
|
|
225
|
+
return "date";
|
|
226
|
+
if (isStringLiteral(token))
|
|
227
|
+
return "string";
|
|
228
|
+
if (isClosingBracket(token))
|
|
229
|
+
return "array";
|
|
230
|
+
if (token.type === "Punctuation" && token.value === ")") {
|
|
231
|
+
const openIdx = findMatchingOpenParen(relevant, i);
|
|
232
|
+
if (openIdx < 1)
|
|
233
|
+
return "unknown";
|
|
234
|
+
const methodToken = relevant[openIdx - 1];
|
|
235
|
+
if (methodToken?.type !== "Identifier")
|
|
236
|
+
return "unknown";
|
|
237
|
+
const hasDot = openIdx >= 2 && isDot(relevant[openIdx - 2]);
|
|
238
|
+
if (!hasDot) {
|
|
239
|
+
// Top-level function call: fn(...)
|
|
240
|
+
const funcEntry = context[methodToken.value];
|
|
241
|
+
if (funcEntry?.type === "function" && funcEntry.return)
|
|
242
|
+
return funcEntry.return;
|
|
243
|
+
return "unknown";
|
|
244
|
+
}
|
|
245
|
+
// Method call: receiver.method(...)
|
|
246
|
+
// First try resolving the receiver as a context object to find a typed method entry
|
|
247
|
+
const receiverPath = buildPathFromTokens(relevant, openIdx - 3);
|
|
248
|
+
if (receiverPath) {
|
|
249
|
+
const receiverEntry = resolveEntry(context, receiverPath);
|
|
250
|
+
if (receiverEntry?.type === "object" && receiverEntry.value != null) {
|
|
251
|
+
const methodVal = receiverEntry.value[methodToken.value];
|
|
252
|
+
const methodEntry = isContextEntry(methodVal) ? methodVal : undefined;
|
|
253
|
+
if (methodEntry?.type === "function" && methodEntry.return)
|
|
254
|
+
return methodEntry.return;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Fall back to builtin method return-type maps (string/array prototype methods)
|
|
258
|
+
const receiverType = resolveTypeOf(relevant, openIdx - 3, context);
|
|
259
|
+
if (receiverType === "string")
|
|
260
|
+
return STRING_METHOD_RETURNS[methodToken.value] ?? "unknown";
|
|
261
|
+
if (receiverType === "array")
|
|
262
|
+
return ARRAY_METHOD_RETURNS[methodToken.value] ?? "unknown";
|
|
263
|
+
if (receiverType === "date")
|
|
264
|
+
return DATE_METHOD_RETURNS[methodToken.value] ?? "unknown";
|
|
265
|
+
return "unknown";
|
|
266
|
+
}
|
|
267
|
+
if (token.type === "Identifier" || token.type === "QuotedIdentifier") {
|
|
268
|
+
const path = buildPathFromTokens(relevant, i);
|
|
269
|
+
if (!path)
|
|
270
|
+
return "unknown";
|
|
271
|
+
const entry = resolveEntry(context, path);
|
|
272
|
+
const kind = entry?.type ?? "unknown";
|
|
273
|
+
if (kind === "string" || kind === "number" || kind === "array" || kind === "object")
|
|
274
|
+
return kind;
|
|
275
|
+
return "unknown";
|
|
276
|
+
}
|
|
277
|
+
return "unknown";
|
|
278
|
+
}
|
|
279
|
+
function analyzeTokens(tokens, cursorPosition, context) {
|
|
280
|
+
const relevant = tokens.filter((t) => t.end <= cursorPosition && t.type !== "EOF" && t.type !== "Whitespace");
|
|
281
|
+
if (relevant.length === 0)
|
|
282
|
+
return { kind: "top-level" };
|
|
283
|
+
let i = relevant.length - 1;
|
|
284
|
+
// Skip the partial word the user is currently typing (only if cursor is at its end)
|
|
285
|
+
if (relevant[i].type === "Identifier" && relevant[i].end === cursorPosition)
|
|
286
|
+
i--;
|
|
287
|
+
if (i < 0)
|
|
288
|
+
return { kind: "top-level" };
|
|
289
|
+
// If the token before the word isn't a dot, check if it's a complete value
|
|
290
|
+
if (!isDot(relevant[i])) {
|
|
291
|
+
if (isCompleteValue(relevant[i]))
|
|
292
|
+
return { kind: "after-value" };
|
|
293
|
+
return { kind: "top-level" };
|
|
294
|
+
}
|
|
295
|
+
// Step over the dot
|
|
296
|
+
i--;
|
|
297
|
+
if (i < 0)
|
|
298
|
+
return { kind: "none" };
|
|
299
|
+
const beforeDot = relevant[i];
|
|
300
|
+
// "hello". or `hello`. → string methods
|
|
301
|
+
if (isStringLiteral(beforeDot))
|
|
302
|
+
return { kind: "string-literal" };
|
|
303
|
+
// [1,2,3]. → array methods
|
|
304
|
+
if (isClosingBracket(beforeDot))
|
|
305
|
+
return { kind: "array-literal" };
|
|
306
|
+
// d"2023-02-11". → date methods
|
|
307
|
+
if (beforeDot.type === "DateLiteral")
|
|
308
|
+
return { kind: "date-value" };
|
|
309
|
+
// fn(). → resolve call return type recursively
|
|
310
|
+
if (beforeDot.type === "Punctuation" && beforeDot.value === ")") {
|
|
311
|
+
const resultType = resolveTypeOf(relevant, i, context);
|
|
312
|
+
if (resultType === "string")
|
|
313
|
+
return { kind: "string-literal" };
|
|
314
|
+
if (resultType === "number")
|
|
315
|
+
return { kind: "number-value" };
|
|
316
|
+
if (resultType === "array")
|
|
317
|
+
return { kind: "array-literal" };
|
|
318
|
+
if (resultType === "date")
|
|
319
|
+
return { kind: "date-value" };
|
|
320
|
+
return { kind: "none" };
|
|
321
|
+
}
|
|
322
|
+
// identifier chain: walk back through alternating Identifier / QuotedIdentifier / dot tokens
|
|
323
|
+
if (beforeDot.type === "Identifier" || beforeDot.type === "QuotedIdentifier") {
|
|
324
|
+
const tokenName = (t) => (t.type === "QuotedIdentifier" ? t.value.slice(2, -1) : t.value);
|
|
325
|
+
const path = [tokenName(beforeDot)];
|
|
326
|
+
i--;
|
|
327
|
+
while (i >= 1) {
|
|
328
|
+
if (!isDot(relevant[i]))
|
|
329
|
+
break;
|
|
330
|
+
i--;
|
|
331
|
+
if (relevant[i].type !== "Identifier" && relevant[i].type !== "QuotedIdentifier")
|
|
332
|
+
break;
|
|
333
|
+
path.unshift(tokenName(relevant[i]));
|
|
334
|
+
i--;
|
|
335
|
+
}
|
|
336
|
+
return { kind: "context-path", path };
|
|
337
|
+
}
|
|
338
|
+
return { kind: "none" };
|
|
339
|
+
}
|
|
340
|
+
const VALID_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
341
|
+
function objectCompletions(obj) {
|
|
342
|
+
return Object.entries(obj).map(([key, val]) => ({
|
|
343
|
+
label: key,
|
|
344
|
+
kind: isContextEntry(val) ? val.type : kindOf(val),
|
|
345
|
+
id: key,
|
|
346
|
+
value: VALID_IDENTIFIER.test(key) ? undefined : `@"${key}"`,
|
|
347
|
+
}));
|
|
348
|
+
}
|
|
349
|
+
function builtinCompletions(methods) {
|
|
350
|
+
return methods.map((m) => ({ label: m.label, kind: m.kind, id: m.label, value: m.value }));
|
|
351
|
+
}
|
|
352
|
+
function binaryOperatorCompletions() {
|
|
353
|
+
return builtinCompletions(BINARY_OPERATORS);
|
|
354
|
+
}
|
|
355
|
+
export function createCompletionProvider(context) {
|
|
356
|
+
return function completionProvider(tokens, cursorPosition) {
|
|
357
|
+
const analysis = analyzeTokens(tokens, cursorPosition, context);
|
|
358
|
+
switch (analysis.kind) {
|
|
359
|
+
case "top-level":
|
|
360
|
+
return objectCompletions(context);
|
|
361
|
+
case "string-literal":
|
|
362
|
+
return builtinCompletions(STRING_METHODS);
|
|
363
|
+
case "number-value":
|
|
364
|
+
return builtinCompletions(NUMBER_METHODS);
|
|
365
|
+
case "date-value":
|
|
366
|
+
return builtinCompletions(DATE_METHODS);
|
|
367
|
+
case "array-literal":
|
|
368
|
+
return builtinCompletions(ARRAY_METHODS);
|
|
369
|
+
case "context-path": {
|
|
370
|
+
const entry = resolveEntry(context, analysis.path);
|
|
371
|
+
if (!entry)
|
|
372
|
+
return [];
|
|
373
|
+
if (entry.type === "string")
|
|
374
|
+
return builtinCompletions(STRING_METHODS);
|
|
375
|
+
if (entry.type === "number")
|
|
376
|
+
return builtinCompletions(NUMBER_METHODS);
|
|
377
|
+
if (entry.type === "array")
|
|
378
|
+
return builtinCompletions(ARRAY_METHODS);
|
|
379
|
+
if (entry.type === "date")
|
|
380
|
+
return builtinCompletions(DATE_METHODS);
|
|
381
|
+
if (entry.type === "object" && entry.value != null && typeof entry.value === "object")
|
|
382
|
+
return objectCompletions(entry.value);
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
case "after-value":
|
|
386
|
+
return binaryOperatorCompletions();
|
|
387
|
+
case "none":
|
|
388
|
+
return [];
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|