@valbuild/core 0.25.0 → 0.27.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 (94) hide show
  1. package/dist/declarations/src/selector/future/index.d.ts +1 -1
  2. package/dist/declarations/src/source/future/i18n.d.ts +1 -1
  3. package/package.json +12 -3
  4. package/CHANGELOG.md +0 -0
  5. package/ROADMAP.md +0 -106
  6. package/jest.config.js +0 -4
  7. package/src/Json.ts +0 -4
  8. package/src/ValApi.ts +0 -81
  9. package/src/expr/README.md +0 -193
  10. package/src/expr/eval.test.ts +0 -198
  11. package/src/expr/eval.ts +0 -251
  12. package/src/expr/expr.ts +0 -91
  13. package/src/expr/index.ts +0 -3
  14. package/src/expr/parser.test.ts +0 -158
  15. package/src/expr/parser.ts +0 -229
  16. package/src/expr/repl.ts +0 -88
  17. package/src/expr/tokenizer.test.ts +0 -539
  18. package/src/expr/tokenizer.ts +0 -117
  19. package/src/fp/array.ts +0 -30
  20. package/src/fp/index.ts +0 -3
  21. package/src/fp/result.ts +0 -214
  22. package/src/fp/util.ts +0 -52
  23. package/src/future/fetchVal.test.ts +0 -164
  24. package/src/future/fetchVal.ts +0 -206
  25. package/src/getSha256.ts +0 -8
  26. package/src/index.ts +0 -132
  27. package/src/initSchema.ts +0 -50
  28. package/src/initVal.ts +0 -73
  29. package/src/module.test.ts +0 -170
  30. package/src/module.ts +0 -397
  31. package/src/patch/deref.test.ts +0 -298
  32. package/src/patch/deref.ts +0 -136
  33. package/src/patch/index.ts +0 -12
  34. package/src/patch/json.test.ts +0 -582
  35. package/src/patch/json.ts +0 -304
  36. package/src/patch/operation.ts +0 -86
  37. package/src/patch/ops.ts +0 -83
  38. package/src/patch/parse.test.ts +0 -202
  39. package/src/patch/parse.ts +0 -202
  40. package/src/patch/patch.ts +0 -49
  41. package/src/patch/util.ts +0 -74
  42. package/src/schema/array.ts +0 -93
  43. package/src/schema/boolean.ts +0 -49
  44. package/src/schema/future/i18n.ts +0 -69
  45. package/src/schema/future/oneOf.ts +0 -63
  46. package/src/schema/image.ts +0 -137
  47. package/src/schema/index.ts +0 -70
  48. package/src/schema/keyOf.ts +0 -167
  49. package/src/schema/literal.ts +0 -63
  50. package/src/schema/number.ts +0 -56
  51. package/src/schema/object.ts +0 -110
  52. package/src/schema/record.ts +0 -103
  53. package/src/schema/richtext.ts +0 -44
  54. package/src/schema/string.ts +0 -95
  55. package/src/schema/union.ts +0 -63
  56. package/src/schema/validation/ValidationError.ts +0 -16
  57. package/src/schema/validation/ValidationFix.ts +0 -6
  58. package/src/schema/validation.test.ts +0 -291
  59. package/src/selector/SelectorProxy.ts +0 -238
  60. package/src/selector/array.ts +0 -13
  61. package/src/selector/boolean.ts +0 -4
  62. package/src/selector/file.ts +0 -6
  63. package/src/selector/future/ExprProxy.test.ts +0 -203
  64. package/src/selector/future/ExprProxy.ts +0 -216
  65. package/src/selector/future/SelectorProxy.test.ts +0 -172
  66. package/src/selector/future/SelectorProxy.ts +0 -238
  67. package/src/selector/future/array.ts +0 -37
  68. package/src/selector/future/boolean.ts +0 -4
  69. package/src/selector/future/file.ts +0 -14
  70. package/src/selector/future/i18n.ts +0 -13
  71. package/src/selector/future/index.ts +0 -169
  72. package/src/selector/future/number.ts +0 -4
  73. package/src/selector/future/object.ts +0 -22
  74. package/src/selector/future/primitive.ts +0 -17
  75. package/src/selector/future/remote.ts +0 -9
  76. package/src/selector/future/selector.test.ts +0 -429
  77. package/src/selector/future/selectorOf.ts +0 -7
  78. package/src/selector/future/string.ts +0 -4
  79. package/src/selector/index.ts +0 -121
  80. package/src/selector/number.ts +0 -4
  81. package/src/selector/object.ts +0 -5
  82. package/src/selector/primitive.ts +0 -4
  83. package/src/selector/string.ts +0 -4
  84. package/src/source/file.ts +0 -45
  85. package/src/source/future/i18n.ts +0 -60
  86. package/src/source/future/remote.ts +0 -54
  87. package/src/source/index.ts +0 -53
  88. package/src/source/link.ts +0 -14
  89. package/src/source/richtext.ts +0 -178
  90. package/src/val/array.ts +0 -10
  91. package/src/val/index.ts +0 -100
  92. package/src/val/object.ts +0 -13
  93. package/src/val/primitive.ts +0 -8
  94. package/tsconfig.json +0 -8
@@ -11,7 +11,7 @@ import { Source, SourceArray, SourceObject, SourcePrimitive } from "../../source
11
11
  import { Schema } from "../../schema/index.js";
12
12
  import { Expr } from "../../expr/expr.js";
13
13
  import { RemoteSelector } from "./remote.js";
14
- import { A } from "ts-toolbelt";
14
+ import type { A } from "ts-toolbelt";
15
15
  import { I18nSource, I18nCompatibleSource } from "../../source/future/i18n.js";
16
16
  import { RemoteCompatibleSource, RemoteSource } from "../../source/future/remote.js";
17
17
  import { FileSource } from "../../source/file.js";
@@ -1,4 +1,4 @@
1
- import { F } from "ts-toolbelt";
1
+ import type { F } from "ts-toolbelt";
2
2
  import { SourcePrimitive, VAL_EXTENSION } from "../index.js";
3
3
  import { FileSource } from "../file.js";
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valbuild/core",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "private": false,
5
5
  "description": "Val - supercharged hard-coded content",
6
6
  "scripts": {
@@ -39,8 +39,17 @@
39
39
  ],
40
40
  "exports": true
41
41
  },
42
- "devDependencies": {
42
+ "devDependencies": {},
43
+ "dependencies": {
43
44
  "ts-toolbelt": "^9.6.0"
44
45
  },
45
- "dependencies": {}
46
+ "files": [
47
+ "dist",
48
+ "fp/dist",
49
+ "fp/package.json",
50
+ "expr/dist",
51
+ "expr/package.json",
52
+ "patch/dist",
53
+ "patch/package.json"
54
+ ]
46
55
  }
package/CHANGELOG.md DELETED
File without changes
package/ROADMAP.md DELETED
@@ -1,106 +0,0 @@
1
- # Planned features
2
-
3
- ## i18n
4
-
5
- Example:
6
-
7
- ```tsx
8
- // file: ./blogs.val.ts
9
-
10
- export const schema = s.array(
11
- s.i18n(s.object({ title: s.string(), text: s.richtext() }))
12
- );
13
-
14
- export default val.content("/blogs", schema, [
15
- {
16
- en_US: {
17
- title: "Title 1",
18
- text: val.richtext("Richtext 1"),
19
- },
20
- nb_NO: {
21
- title: "Tittel 1",
22
- text: val.richtext("Riktekst?"),
23
- },
24
- },
25
- ]);
26
-
27
- // file: ./components/ServerComponent.ts
28
-
29
- import blogsVal from "./blogs.val";
30
-
31
- export async function ServerComponent({ index }: { index: number }) {
32
- const blogs = await fetchVal(blogVal, getLocale());
33
-
34
- // NOTE: automatically resolves the locale
35
- const title = blogs[index].title; // is a string
36
- return <div>{title}</div>;
37
- }
38
- ```
39
-
40
- Missing infrastructure: none in particular.
41
-
42
- ## remote
43
-
44
- Remote makes it possible to move content to cloud storage (and back again). It uses immutable references, so local work, branches still works.
45
-
46
- Example:
47
-
48
- ```tsx
49
- // file: ./blogs.val.ts
50
-
51
- export const schema = s
52
- .array(s.object({ title: s.string(), text: s.richtext() }))
53
- .remote();
54
-
55
- export default val.content(
56
- "/blogs",
57
- schema,
58
- val.remote("4ba7c33b32a60be06b1b26dff8cc5d8d967660ab") // a change in content, will result in a new reference
59
- );
60
-
61
- // file: ./components/ServerComponent.ts
62
-
63
- import blogsVal from "./blogs.val";
64
-
65
- export async function ServerComponent({ index }: { index: number }) {
66
- const blog = await fetchVal(
67
- blogVal[index] // only fetch the blog at index
68
- );
69
- const title = blog.title;
70
- return <div>{title}</div>;
71
- }
72
- ```
73
-
74
- Missing infrastructure: cloud support, patch support, selectors proxy needs to be able to switch between remote and source (see selectors/future), editor plugin to improve DX (refactors, ...)?
75
-
76
- ## oneOf
77
-
78
- oneOf makes it possible to reference an item in an array of in another val module.
79
-
80
- Example:
81
-
82
- ```ts
83
- // file: ./employees.val.ts
84
-
85
- export schema = s.array(s.object({ name: s.string() }));
86
-
87
- export default val.content('/employees', schema, [{
88
- name: 'John Smith',
89
- }]);
90
-
91
- // file: ./contacts.val.ts
92
-
93
- import employeesVal from './employees.val';
94
-
95
- export schema = s.object({
96
- hr: s.oneOf(employeesVal),
97
- });
98
-
99
- export default val.content('/contacts', schema, {
100
- hr: employeesVal[0]
101
- });
102
-
103
-
104
- ```
105
-
106
- Missing infrastructure: need a change in how patches are applied for source files to handle selectors inside data.
package/jest.config.js DELETED
@@ -1,4 +0,0 @@
1
- /** @type {import("jest").Config} */
2
- module.exports = {
3
- preset: "../../jest.preset",
4
- };
package/src/Json.ts DELETED
@@ -1,4 +0,0 @@
1
- export type Json = JsonPrimitive | JsonObject | JsonArray;
2
- export type JsonPrimitive = string | number | boolean | null;
3
- export type JsonArray = readonly Json[];
4
- export type JsonObject = { readonly [key in string]: Json };
package/src/ValApi.ts DELETED
@@ -1,81 +0,0 @@
1
- import { ApiPatchResponse, ApiTreeResponse } from ".";
2
- import { result } from "./fp";
3
- import { PatchJSON } from "./patch";
4
- import { ModuleId } from "./val";
5
-
6
- type FetchError = { message: string; statusCode?: number };
7
-
8
- // TODO: move this to internal, only reason this is here is that react, ui and server all depend on it
9
- export class ValApi {
10
- constructor(public host: string) {}
11
-
12
- getDisableUrl() {
13
- return `${this.host}/disable`;
14
- }
15
- getEditUrl() {
16
- return `${this.host}/static/edit`;
17
- }
18
-
19
- postPatches(
20
- moduleId: ModuleId,
21
- patches: PatchJSON,
22
- headers?: Record<string, string> | undefined
23
- ) {
24
- return fetch(`${this.host}/patches/~`, {
25
- headers: headers || {
26
- "Content-Type": "application/json",
27
- },
28
- method: "POST",
29
- body: JSON.stringify({ [moduleId]: patches }),
30
- }).then((res) => parse<ApiPatchResponse>(res));
31
- }
32
-
33
- getSession() {
34
- return fetch(`${this.host}/session`).then((res) =>
35
- parse<{
36
- mode: "proxy" | "local";
37
- member_role: "owner" | "developer" | "editor";
38
- }>(res)
39
- );
40
- }
41
-
42
- getModules({
43
- patch = false,
44
- includeSchema = false,
45
- includeSource = false,
46
- treePath = "/",
47
- headers,
48
- }: {
49
- patch?: boolean;
50
- includeSchema?: boolean;
51
- includeSource?: boolean;
52
- treePath?: string;
53
- headers?: Record<string, string> | undefined;
54
- }) {
55
- const params = new URLSearchParams();
56
- params.set("patch", patch.toString());
57
- params.set("schema", includeSchema.toString());
58
- params.set("source", includeSource.toString());
59
- return fetch(`${this.host}/tree/~${treePath}?${params.toString()}`, {
60
- headers,
61
- }).then((res) => parse<ApiTreeResponse>(res));
62
- }
63
- }
64
-
65
- // TODO: validate
66
- async function parse<T>(res: Response): Promise<result.Result<T, FetchError>> {
67
- try {
68
- if (res.ok) {
69
- return result.ok(await res.json());
70
- } else {
71
- return result.err({
72
- statusCode: res.status,
73
- message: await res.text(),
74
- });
75
- }
76
- } catch (err) {
77
- return result.err({
78
- message: err instanceof Error ? err.message : "Unknown error",
79
- });
80
- }
81
- }
@@ -1,193 +0,0 @@
1
- # Visp
2
-
3
- Visp (as in Val Lisp or whisk in Norwegian) is a Lisp used to serialize Val `Selector`s.
4
-
5
- It is an INTERNAL language - it is NOT designed to be used by end-users.
6
- This document is architectural overview for this INTERNAL language - it is documentation for developers working on Val.
7
-
8
- Visp exists since Val clients must be able to execute remote `Selector`s.
9
- See the docs for remote `Schema`s for more about this.
10
-
11
- The design goals are as follows:
12
-
13
- - evaluate to `Val` objects
14
- - easy to parse and serialize
15
- - easy to evaluate in JavaScript
16
- - readable by Vals developers (for internal debugging)
17
- - stable language semantics to avoid breaking changes as Visp is part of the (internal) API versioning
18
- - does not support more functionality than what is required to serialize `Selector`s
19
-
20
- The non-goals are:
21
-
22
- - Visp does not need to be convenient to write - `Selector`s are used to write it
23
- - Visp does not need to be easily understandable by end-users of Val
24
-
25
- ## Syntax
26
-
27
- Visp is a Lisp which only can evaluate one expression at a time.
28
-
29
- Read more about how it works in sections that follows.
30
-
31
- ### Property access
32
-
33
- ```visp
34
- ('title' foo)
35
- ```
36
-
37
- corresponds to:
38
-
39
- ```js
40
- foo["title"];
41
- ```
42
-
43
- There are no numbers in Visp, so arrays are indexed in the same way:
44
-
45
- ```visp
46
- ('0' foo)
47
- ```
48
-
49
- corresponds to:
50
-
51
- ```js
52
- foo["0"]; // same as foo[0]
53
- ```
54
-
55
- ### Function calls
56
-
57
- Function calls are similar to property access, but with arguments separated by whitespace:
58
-
59
- ```visp
60
- (fnname foo arg1 arg2)
61
- ```
62
-
63
- corresponds to:
64
-
65
- ```js
66
- foo["fnname"](arg1, arg2); // same as foo.fname(arg1, arg2)
67
- ```
68
-
69
- #### Higher order functions
70
-
71
- Higher order functions must be prefixed with the `!` character.
72
- Arguments can be accessed using the `@` character. The `@` must be suffixed with indexes, e.g. `@[0,0]`, the first one corresponding to the stack depth and the second corresponds to index of the argument list.
73
-
74
- ```visp
75
- !(map foo @[0,0])
76
- ```
77
-
78
- corresponds to:
79
-
80
- ```js
81
- foo.map((v) => v);
82
- ```
83
-
84
- Here we access the second argument of a function:
85
-
86
- ```visp
87
- !(map foo @[0,1])
88
- ```
89
-
90
- corresponds to:
91
-
92
- ```js
93
- foo.map((_, i) => i);
94
- ```
95
-
96
- This example shows how higher functions and arguments can be nested:
97
-
98
- ```visp
99
- !(map foo !(map @[0,0] (slice @[1,0] @[0,1])))
100
- ```
101
-
102
- corresponds to:
103
-
104
- ```js
105
- foo.map((v, i) => v.map((j) => j.slice(i)));
106
- ```
107
-
108
- ### Literals
109
-
110
- Visp only supports string literals.
111
-
112
- Example:
113
-
114
- ```visp
115
- 'foo'
116
- ```
117
-
118
- corresponds to:
119
-
120
- ```js
121
- "foo";
122
- ```
123
-
124
- ### String templates
125
-
126
- Val has support for string templates similar to JavaScript.
127
- They are denoted using single quotes `'` (as string literal), but can inject expressions using `${}`.
128
-
129
- Example:
130
-
131
- ```visp
132
- 'foo ${('title' obj)} bar'
133
- ```
134
-
135
- corresponds to:
136
-
137
- ```js
138
- `foo ${obj["title"]} bar`;
139
- ```
140
-
141
- ### Special symbols
142
-
143
- ### `()`
144
-
145
- The `()` symbol evaluates to `undefined`.
146
-
147
- #### `@`
148
-
149
- This symbol can be used to access arguments in [higher order functions](#higher-order-functions).
150
-
151
- ### `!`
152
-
153
- This is a prefix to a [higher order function](#higher-order-functions).
154
-
155
- ### val
156
-
157
- The `val` symbol is used to access data from a Val module.
158
-
159
- Example:
160
-
161
- ```visp
162
- (val '/foo/bar`)
163
- ```
164
-
165
- Returns the `Source` of a Val module of id `/foo/bar`.
166
-
167
- ### json
168
-
169
- The `json` symbol is used to parse json strings.
170
-
171
- Example:
172
-
173
- ```visp
174
- (json '{"foo": "bar"}')
175
- ```
176
-
177
- To create numbers, lists etc, the `json` symbol can be used.
178
-
179
- It is also possible to use `json` with string templates:
180
-
181
- ```visp
182
- (json '{ "foo": ${('title' obj)} }')
183
- ```
184
-
185
- corresponds to:
186
-
187
- ```js
188
- JSON.parse(`{ "foo": ${obj["title"]} }`);
189
- ```
190
-
191
- ### More
192
-
193
- More examples can be found in the [eval.test](eval.test.ts)
@@ -1,198 +0,0 @@
1
- import { pipe, result } from "../fp";
2
- import { Path } from "../selector/future";
3
- import { selectorToVal } from "../selector/future/SelectorProxy";
4
- import { Source } from "../source";
5
- import { evaluate } from "./eval";
6
- import { parse } from "./parser";
7
-
8
- const sources = {
9
- "/app/text": "text1",
10
- "/numbers": [0, 1, 2],
11
- "/articles": [{ title: "title1" }, { title: "title2" }],
12
- "/app/blogs": [
13
- { title: "blog1", text: "text1" },
14
- { title: "blog2", text: "text2" },
15
- ],
16
- };
17
-
18
- const EvalTestCases: {
19
- expr: string;
20
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
- expected: result.Result<{ val: Source; [Path]: any }, any>;
22
- focus?: boolean; // use focus to specify a single test case
23
- }[] = [
24
- {
25
- expr: `'hello world'`,
26
- expected: result.ok({ val: "hello world", [Path]: undefined }),
27
- },
28
- {
29
- expr: `(val '/numbers')`,
30
- expected: result.ok({ val: [0, 1, 2], [Path]: "/numbers" }),
31
- },
32
- {
33
- expr: `('hello world')`,
34
- expected: result.ok({ val: "hello world", [Path]: undefined }),
35
- },
36
- {
37
- expr: `()`,
38
- expected: result.ok({ val: null, [Path]: undefined }),
39
- },
40
- {
41
- expr: `(eq 'value' 'show me')`,
42
- expected: result.ok({ val: false, [Path]: undefined }),
43
- },
44
- {
45
- expr: `(eq 'value' 'value')`,
46
- expected: result.ok({ val: true, [Path]: undefined }),
47
- },
48
- {
49
- expr: `!(andThen 'value' 'show me')`,
50
- expected: result.ok({ val: "show me", [Path]: undefined }),
51
- },
52
- {
53
- expr: `!(andThen '' ('do NOT show me'))`,
54
- expected: result.ok({ val: "", [Path]: undefined }),
55
- },
56
- {
57
- expr: `!(andThen 'text1' @[0,0])`,
58
- expected: result.ok({ val: "text1", [Path]: undefined }),
59
- },
60
- {
61
- expr: `(json '1')`,
62
- expected: result.ok({ val: 1, [Path]: undefined }),
63
- },
64
- {
65
- expr: `(json '"1"')`,
66
- expected: result.ok({ val: "1", [Path]: undefined }),
67
- },
68
- {
69
- expr: `(json '{"foo": "bar"}')`,
70
- expected: result.ok({ val: { foo: "bar" }, [Path]: undefined }),
71
- },
72
- {
73
- expr: `(json '\${(json '1')}')`,
74
- expected: result.ok({ val: 1, [Path]: undefined }),
75
- },
76
- {
77
- expr: `(json '\${(json '"1"')}')`,
78
- expected: result.ok({ val: "1", [Path]: undefined }),
79
- },
80
- {
81
- expr: `(json '{"foo": \${(json '"1"')}}')`,
82
- expected: result.ok({
83
- val: {
84
- foo: "1",
85
- },
86
- [Path]: undefined,
87
- }),
88
- },
89
- {
90
- expr: `(json '\${(val '/numbers')}')`,
91
- expected: result.ok({
92
- val: sources["/numbers"],
93
- [Path]: "/numbers",
94
- }),
95
- },
96
- {
97
- expr: `('test' (json '{ "test": \${((json '0') (val '/numbers'))} }'))`,
98
- expected: result.ok({
99
- val: 0,
100
- [Path]: "/numbers.0",
101
- }),
102
- },
103
- {
104
- expr: `((json '1') ('foo' (json '{"foo": \${(val '/numbers')}}')))`,
105
- expected: result.ok({ val: 1, [Path]: "/numbers.1" }),
106
- },
107
- {
108
- expr: `(length (val '/numbers'))`,
109
- expected: result.ok({
110
- val: sources["/numbers"].length,
111
- [Path]: undefined,
112
- }),
113
- },
114
- {
115
- expr: `('0' (val '/articles'))`,
116
- expected: result.ok({
117
- val: sources["/articles"][0],
118
- [Path]: "/articles.0",
119
- }),
120
- },
121
- {
122
- expr: `!(map (val '/articles') @[0,0])`,
123
- expected: result.ok({
124
- val: sources["/articles"].map((v) => v),
125
- [Path]: "/articles",
126
- }),
127
- },
128
- {
129
- expr: `('0' !(map (val '/articles') ('title' @[0,0])))`,
130
- expected: result.ok({
131
- val: sources["/articles"].map((v) => v["title"])[0],
132
- [Path]: '/articles.0."title"',
133
- }),
134
- },
135
- {
136
- expr: `!(map (val '/articles') ('title' @[0,0]))`,
137
- expected: result.ok({
138
- val: sources["/articles"].map((v) => v["title"]),
139
- [Path]: "/articles",
140
- }),
141
- },
142
- {
143
- expr: `(eq !(andThen (val '/app/text') ()) 'foo')`,
144
- expected: result.ok({
145
- val: false,
146
- [Path]: undefined,
147
- }),
148
- },
149
- {
150
- expr: `!(filter (val '/app/blogs') (eq ('title' @[0,0]) 'blog1'))`,
151
- expected: result.ok({
152
- val: [
153
- {
154
- text: "text1",
155
- title: "blog1",
156
- },
157
- ],
158
- [Path]: "/app/blogs",
159
- }),
160
- },
161
- {
162
- expr: `(json '{"title": \${()}}')`,
163
- expected: result.ok({
164
- val: {
165
- title: null,
166
- },
167
-
168
- [Path]: undefined,
169
- }),
170
- },
171
- ];
172
-
173
- describe("eval", () => {
174
- test.each(
175
- EvalTestCases.filter(({ focus }) =>
176
- EvalTestCases.some((v) => v.focus) ? focus : true
177
- )
178
- )('evaluate: "$expr"', ({ expr, expected }) => {
179
- const parseRes = parse(expr);
180
- if (result.isErr(parseRes)) {
181
- return expect(parseRes).toHaveProperty("value");
182
- }
183
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
184
- expect(
185
- pipe(
186
- evaluate(
187
- parseRes.value,
188
- (path) => {
189
- return sources[path as keyof typeof sources];
190
- },
191
- []
192
- ),
193
- result.map((v) => selectorToVal(v))
194
- )
195
- ).toStrictEqual(expected);
196
- });
197
- //
198
- });