@dxos/effect 0.6.14-main.2b6a0f3 → 0.6.14-main.69511f5
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/lib/browser/index.mjs +37 -48
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +41 -39
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +37 -41
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/ast.d.ts +22 -3
- package/dist/types/src/ast.d.ts.map +1 -1
- package/package.json +6 -8
- package/src/ast.test.ts +7 -4
- package/src/ast.ts +55 -11
- package/src/url.ts +1 -1
- package/dist/types/src/decamelize.d.ts +0 -2
- package/dist/types/src/decamelize.d.ts.map +0 -1
- package/src/decamelize.ts +0 -36
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import "@dxos/node-std/globals";
|
|
2
2
|
|
|
3
|
-
// inject-globals:@inject-globals
|
|
4
|
-
import {
|
|
5
|
-
global,
|
|
6
|
-
Buffer,
|
|
7
|
-
process
|
|
8
|
-
} from "@dxos/node-std/inject-globals";
|
|
9
|
-
|
|
10
3
|
// packages/common/effect/src/index.ts
|
|
11
4
|
import { AST as AST3, JSONSchema, Schema as S } from "@effect/schema";
|
|
12
5
|
|
|
@@ -15,6 +8,7 @@ import { AST } from "@effect/schema";
|
|
|
15
8
|
import { Option, pipe } from "effect";
|
|
16
9
|
import { invariant } from "@dxos/invariant";
|
|
17
10
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/effect/src/ast.ts";
|
|
11
|
+
var isLeafType = (node) => !AST.isTupleType(node) && !AST.isTypeLiteral(node);
|
|
18
12
|
var getAnnotation = (annotationId, node) => pipe(AST.getAnnotation(annotationId)(node), Option.getOrUndefined);
|
|
19
13
|
var getType = (node) => {
|
|
20
14
|
if (AST.isUnion(node)) {
|
|
@@ -36,7 +30,7 @@ var getProperty = (schema, path) => {
|
|
|
36
30
|
const type = getType(prop.type);
|
|
37
31
|
invariant(type, `invalid type: ${path}`, {
|
|
38
32
|
F: __dxlog_file,
|
|
39
|
-
L:
|
|
33
|
+
L: 52,
|
|
40
34
|
S: void 0,
|
|
41
35
|
A: [
|
|
42
36
|
"type",
|
|
@@ -47,8 +41,20 @@ var getProperty = (schema, path) => {
|
|
|
47
41
|
}
|
|
48
42
|
return node;
|
|
49
43
|
};
|
|
50
|
-
var
|
|
51
|
-
|
|
44
|
+
var VisitResult;
|
|
45
|
+
(function(VisitResult2) {
|
|
46
|
+
VisitResult2[VisitResult2["CONTINUE"] = 0] = "CONTINUE";
|
|
47
|
+
VisitResult2[VisitResult2["SKIP"] = 1] = "SKIP";
|
|
48
|
+
VisitResult2[VisitResult2["EXIT"] = 2] = "EXIT";
|
|
49
|
+
})(VisitResult || (VisitResult = {}));
|
|
50
|
+
var visit = (node, testOrVisitor, visitor) => {
|
|
51
|
+
if (!visitor) {
|
|
52
|
+
visitNode(node, void 0, testOrVisitor);
|
|
53
|
+
} else {
|
|
54
|
+
visitNode(node, testOrVisitor, visitor);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var visitNode = (node, test, visitor, path = [], depth = 0) => {
|
|
52
58
|
for (const prop of AST.getPropertySignatures(node)) {
|
|
53
59
|
const currentPath = [
|
|
54
60
|
...path,
|
|
@@ -56,12 +62,24 @@ var visitNode = (node, visitor, path = []) => {
|
|
|
56
62
|
];
|
|
57
63
|
const type = getType(prop.type);
|
|
58
64
|
if (type) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
const result = test?.(node, path, depth) ?? 0;
|
|
66
|
+
if (result === 2) {
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
visitor(type, currentPath, depth);
|
|
70
|
+
if (result !== 1) {
|
|
71
|
+
if (AST.isTypeLiteral(type)) {
|
|
72
|
+
visitNode(type, test, visitor, currentPath, depth + 1);
|
|
73
|
+
} else if (AST.isTupleType(type)) {
|
|
74
|
+
for (const [i, elementType] of type.elements.entries()) {
|
|
75
|
+
const type2 = getType(elementType.type);
|
|
76
|
+
if (type2) {
|
|
77
|
+
visitNode(type2, test, visitor, [
|
|
78
|
+
i,
|
|
79
|
+
...currentPath
|
|
80
|
+
], depth);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
65
83
|
}
|
|
66
84
|
}
|
|
67
85
|
}
|
|
@@ -71,38 +89,7 @@ var visitNode = (node, visitor, path = []) => {
|
|
|
71
89
|
// packages/common/effect/src/url.ts
|
|
72
90
|
import { AST as AST2 } from "@effect/schema";
|
|
73
91
|
import { Option as Option2, pipe as pipe2 } from "effect";
|
|
74
|
-
|
|
75
|
-
// packages/common/effect/src/decamelize.ts
|
|
76
|
-
var LOW_DASH = "_".codePointAt(0);
|
|
77
|
-
var SMALL_A = "a".codePointAt(0);
|
|
78
|
-
var CAPITAL_A = "A".codePointAt(0);
|
|
79
|
-
var SMALL_Z = "z".codePointAt(0);
|
|
80
|
-
var CAPITAL_Z = "Z".codePointAt(0);
|
|
81
|
-
var isLower = (char) => char >= SMALL_A && char <= SMALL_Z;
|
|
82
|
-
var isUpper = (char) => char >= CAPITAL_A && char <= CAPITAL_Z;
|
|
83
|
-
var toLower = (char) => char + 32;
|
|
84
|
-
var decamelize = (str) => {
|
|
85
|
-
const firstChar = str.charCodeAt(0);
|
|
86
|
-
if (!isLower(firstChar)) {
|
|
87
|
-
return str;
|
|
88
|
-
}
|
|
89
|
-
const length = str.length;
|
|
90
|
-
let changed = false;
|
|
91
|
-
const out = [];
|
|
92
|
-
for (let i = 0; i < length; ++i) {
|
|
93
|
-
const c = str.charCodeAt(i);
|
|
94
|
-
if (isUpper(c)) {
|
|
95
|
-
out.push(LOW_DASH);
|
|
96
|
-
out.push(toLower(c));
|
|
97
|
-
changed = true;
|
|
98
|
-
} else {
|
|
99
|
-
out.push(c);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return changed ? String.fromCharCode.apply(void 0, out) : str;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
// packages/common/effect/src/url.ts
|
|
92
|
+
import { decamelize } from "@dxos/util";
|
|
106
93
|
var ParamKeyAnnotationId = Symbol.for("@dxos/schema/annotation/ParamKey");
|
|
107
94
|
var getParamKeyAnnotation = AST2.getAnnotation(ParamKeyAnnotationId);
|
|
108
95
|
var ParamKeyAnnotation = (value) => (self) => self.annotations({
|
|
@@ -159,10 +146,12 @@ export {
|
|
|
159
146
|
ParamKeyAnnotation,
|
|
160
147
|
S,
|
|
161
148
|
UrlParser,
|
|
149
|
+
VisitResult,
|
|
162
150
|
getAnnotation,
|
|
163
151
|
getParamKeyAnnotation,
|
|
164
152
|
getProperty,
|
|
165
153
|
getType,
|
|
154
|
+
isLeafType,
|
|
166
155
|
visit
|
|
167
156
|
};
|
|
168
157
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/ast.ts", "../../../src/url.ts"
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { AST, JSONSchema, Schema as S } from '@effect/schema';\nimport type * as Types from 'effect/Types';\n\nexport { AST, JSONSchema, S, Types };\n\nexport * from './ast';\nexport * from './url';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { invariant } from '@dxos/invariant';\n\n//\n// Refs\n// https://effect.website/docs/guides/schema\n// https://www.npmjs.com/package/@effect/schema\n// https://effect-ts.github.io/effect/schema/AST.ts.html\n//\n\n/**\n * Get annotation or return undefined.\n */\nexport const getAnnotation = <T>(annotationId: symbol, node: AST.Annotated): T | undefined =>\n pipe(AST.getAnnotation<T>(annotationId)(node), Option.getOrUndefined);\n\n/**\n * Get type node.\n */\nexport const getType = (node: AST.AST): AST.AST | undefined => {\n if (AST.isUnion(node)) {\n return node.types.find((type) => getType(type));\n } else if (AST.isRefinement(node)) {\n return getType(node.from);\n } else {\n return node;\n }\n};\n\n/**\n * Get the AST node for the given property (dot-path).\n */\nexport const getProperty = (schema: S.Schema<any>, path: string): AST.AST | undefined => {\n let node: AST.AST = schema.ast;\n for (const part of path.split('.')) {\n const props = AST.getPropertySignatures(node);\n const prop = props.find((prop) => prop.name === part);\n if (!prop) {\n return undefined;\n }\n\n // TODO(burdon): Check if leaf.\n const type = getType(prop.type);\n invariant(type, `invalid type: ${path}`);\n node = type;\n }\n\n return node;\n};\n\nexport type
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["AST", "JSONSchema", "Schema", "S", "AST", "Option", "pipe", "invariant", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/ast.ts", "../../../src/url.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { AST, JSONSchema, Schema as S } from '@effect/schema';\nimport type * as Types from 'effect/Types';\n\nexport { AST, JSONSchema, S, Types };\n\nexport * from './ast';\nexport * from './url';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { invariant } from '@dxos/invariant';\n\n//\n// Refs\n// https://effect.website/docs/guides/schema\n// https://www.npmjs.com/package/@effect/schema\n// https://effect-ts.github.io/effect/schema/AST.ts.html\n//\n\nexport const isLeafType = (node: AST.AST) => !AST.isTupleType(node) && !AST.isTypeLiteral(node);\n\n/**\n * Get annotation or return undefined.\n */\nexport const getAnnotation = <T>(annotationId: symbol, node: AST.Annotated): T | undefined =>\n pipe(AST.getAnnotation<T>(annotationId)(node), Option.getOrUndefined);\n\n/**\n * Get type node.\n */\nexport const getType = (node: AST.AST): AST.AST | undefined => {\n if (AST.isUnion(node)) {\n return node.types.find((type) => getType(type));\n } else if (AST.isRefinement(node)) {\n return getType(node.from);\n } else {\n return node;\n }\n};\n\n/**\n * Get the AST node for the given property (dot-path).\n */\nexport const getProperty = (schema: S.Schema<any>, path: string): AST.AST | undefined => {\n let node: AST.AST = schema.ast;\n for (const part of path.split('.')) {\n const props = AST.getPropertySignatures(node);\n const prop = props.find((prop) => prop.name === part);\n if (!prop) {\n return undefined;\n }\n\n // TODO(burdon): Check if leaf.\n const type = getType(prop.type);\n invariant(type, `invalid type: ${path}`);\n node = type;\n }\n\n return node;\n};\n\nexport enum VisitResult {\n CONTINUE = 0,\n /**\n * Skip visiting children.\n */\n SKIP = 1,\n /**\n * Stop traversing immeditaely.\n */\n EXIT = 2,\n}\n\nexport type Path = (string | number)[];\n\nexport type Tester = (node: AST.AST, path: Path, depth: number) => VisitResult;\nexport type Visitor = (node: AST.AST, path: Path, depth: number) => void;\n\n/**\n * Visit leaf nodes.\n * Refs:\n * - https://github.com/syntax-tree/unist-util-visit?tab=readme-ov-file#visitor\n * - https://github.com/syntax-tree/unist-util-is?tab=readme-ov-file#test\n */\nexport const visit: {\n (node: AST.AST, visitor: Visitor): void;\n (node: AST.AST, test: Tester, visitor: Visitor): void;\n} = (node: AST.AST, testOrVisitor: Tester | Visitor, visitor?: Visitor): void => {\n if (!visitor) {\n visitNode(node, undefined, testOrVisitor);\n } else {\n visitNode(node, testOrVisitor as Tester, visitor);\n }\n};\n\nconst visitNode = (\n node: AST.AST,\n test: Tester | undefined,\n visitor: Visitor,\n path: Path = [],\n depth = 0,\n): VisitResult | undefined => {\n for (const prop of AST.getPropertySignatures(node)) {\n const currentPath = [...path, prop.name.toString()];\n const type = getType(prop.type);\n if (type) {\n const result = test?.(node, path, depth) ?? VisitResult.CONTINUE;\n if (result === VisitResult.EXIT) {\n return result;\n }\n\n visitor(type, currentPath, depth);\n\n if (result !== VisitResult.SKIP) {\n if (AST.isTypeLiteral(type)) {\n visitNode(type, test, visitor, currentPath, depth + 1);\n } else if (AST.isTupleType(type)) {\n for (const [i, elementType] of type.elements.entries()) {\n const type = getType(elementType.type);\n if (type) {\n visitNode(type, test, visitor, [i, ...currentPath], depth);\n }\n }\n }\n }\n }\n }\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { decamelize } from '@dxos/util';\n\nconst ParamKeyAnnotationId = Symbol.for('@dxos/schema/annotation/ParamKey');\n\ntype ParamKeyAnnotationValue = { key: string };\n\nexport const getParamKeyAnnotation: (annotated: AST.Annotated) => Option.Option<ParamKeyAnnotationValue> =\n AST.getAnnotation<ParamKeyAnnotationValue>(ParamKeyAnnotationId);\n\nexport const ParamKeyAnnotation =\n (value: ParamKeyAnnotationValue) =>\n <S extends S.Annotable.All>(self: S): S.Annotable.Self<S> =>\n self.annotations({ [ParamKeyAnnotationId]: value });\n\n/**\n * HTTP params parser.\n * Supports custom key serialization.\n */\nexport class UrlParser<T extends Record<string, any>> {\n constructor(private readonly _schema: S.Struct<T>) {}\n\n /**\n * Parse URL params.\n */\n parse(_url: string): T {\n const url = new URL(_url);\n return Object.entries(this._schema.fields).reduce<Record<string, any>>((params, [key, type]) => {\n let value = url.searchParams.get(decamelize(key));\n if (value == null) {\n value = url.searchParams.get(key);\n }\n\n if (value != null) {\n if (AST.isNumberKeyword(type.ast)) {\n params[key] = parseInt(value);\n } else if (AST.isBooleanKeyword(type.ast)) {\n params[key] = value === 'true' || value === '1';\n } else {\n params[key] = value;\n }\n }\n\n return params;\n }, {}) as T;\n }\n\n /**\n * Return URL with encoded params.\n */\n create(_url: string, params: T): URL {\n const url = new URL(_url);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n const field = this._schema.fields[key];\n if (field) {\n const { key: serializedKey } = pipe(\n getParamKeyAnnotation(field.ast),\n Option.getOrElse(() => ({\n key: decamelize(key),\n })),\n );\n\n url.searchParams.set(serializedKey, String(value));\n }\n }\n });\n\n return url;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["AST", "JSONSchema", "Schema", "S", "AST", "Option", "pipe", "invariant", "isLeafType", "node", "isTupleType", "isTypeLiteral", "getAnnotation", "annotationId", "getOrUndefined", "getType", "isUnion", "types", "find", "type", "isRefinement", "from", "getProperty", "schema", "path", "ast", "part", "split", "props", "getPropertySignatures", "prop", "name", "undefined", "VisitResult", "visit", "testOrVisitor", "visitor", "visitNode", "test", "depth", "currentPath", "toString", "result", "i", "elementType", "elements", "entries", "AST", "Option", "pipe", "decamelize", "ParamKeyAnnotationId", "Symbol", "for", "getParamKeyAnnotation", "AST", "getAnnotation", "ParamKeyAnnotation", "value", "self", "annotations", "UrlParser", "constructor", "_schema", "parse", "_url", "url", "URL", "Object", "entries", "fields", "reduce", "params", "key", "type", "searchParams", "get", "decamelize", "isNumberKeyword", "ast", "parseInt", "isBooleanKeyword", "create", "forEach", "undefined", "field", "serializedKey", "pipe", "Option", "getOrElse", "set", "String"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"
|
|
1
|
+
{"inputs":{"packages/common/effect/src/ast.ts":{"bytes":11581,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true}],"format":"esm"},"packages/common/effect/src/url.ts":{"bytes":7711,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/common/effect/src/index.ts":{"bytes":1034,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"packages/common/effect/src/ast.ts","kind":"import-statement","original":"./ast"},{"path":"packages/common/effect/src/url.ts","kind":"import-statement","original":"./url"}],"format":"esm"}},"outputs":{"packages/common/effect/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":10203},"packages/common/effect/dist/lib/browser/index.mjs":{"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["AST","JSONSchema","ParamKeyAnnotation","S","UrlParser","VisitResult","getAnnotation","getParamKeyAnnotation","getProperty","getType","isLeafType","visit"],"entryPoint":"packages/common/effect/src/index.ts","inputs":{"packages/common/effect/src/index.ts":{"bytesInOutput":71},"packages/common/effect/src/ast.ts":{"bytesInOutput":2437},"packages/common/effect/src/url.ts":{"bytesInOutput":1624}},"bytes":4502}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -23,10 +23,12 @@ __export(node_exports, {
|
|
|
23
23
|
ParamKeyAnnotation: () => ParamKeyAnnotation,
|
|
24
24
|
S: () => import_schema.Schema,
|
|
25
25
|
UrlParser: () => UrlParser,
|
|
26
|
+
VisitResult: () => VisitResult,
|
|
26
27
|
getAnnotation: () => getAnnotation,
|
|
27
28
|
getParamKeyAnnotation: () => getParamKeyAnnotation,
|
|
28
29
|
getProperty: () => getProperty,
|
|
29
30
|
getType: () => getType,
|
|
31
|
+
isLeafType: () => isLeafType,
|
|
30
32
|
visit: () => visit
|
|
31
33
|
});
|
|
32
34
|
module.exports = __toCommonJS(node_exports);
|
|
@@ -36,7 +38,9 @@ var import_effect = require("effect");
|
|
|
36
38
|
var import_invariant = require("@dxos/invariant");
|
|
37
39
|
var import_schema3 = require("@effect/schema");
|
|
38
40
|
var import_effect2 = require("effect");
|
|
41
|
+
var import_util = require("@dxos/util");
|
|
39
42
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/effect/src/ast.ts";
|
|
43
|
+
var isLeafType = (node) => !import_schema2.AST.isTupleType(node) && !import_schema2.AST.isTypeLiteral(node);
|
|
40
44
|
var getAnnotation = (annotationId, node) => (0, import_effect.pipe)(import_schema2.AST.getAnnotation(annotationId)(node), import_effect.Option.getOrUndefined);
|
|
41
45
|
var getType = (node) => {
|
|
42
46
|
if (import_schema2.AST.isUnion(node)) {
|
|
@@ -58,7 +62,7 @@ var getProperty = (schema, path) => {
|
|
|
58
62
|
const type = getType(prop.type);
|
|
59
63
|
(0, import_invariant.invariant)(type, `invalid type: ${path}`, {
|
|
60
64
|
F: __dxlog_file,
|
|
61
|
-
L:
|
|
65
|
+
L: 52,
|
|
62
66
|
S: void 0,
|
|
63
67
|
A: [
|
|
64
68
|
"type",
|
|
@@ -69,8 +73,20 @@ var getProperty = (schema, path) => {
|
|
|
69
73
|
}
|
|
70
74
|
return node;
|
|
71
75
|
};
|
|
72
|
-
var
|
|
73
|
-
|
|
76
|
+
var VisitResult;
|
|
77
|
+
(function(VisitResult2) {
|
|
78
|
+
VisitResult2[VisitResult2["CONTINUE"] = 0] = "CONTINUE";
|
|
79
|
+
VisitResult2[VisitResult2["SKIP"] = 1] = "SKIP";
|
|
80
|
+
VisitResult2[VisitResult2["EXIT"] = 2] = "EXIT";
|
|
81
|
+
})(VisitResult || (VisitResult = {}));
|
|
82
|
+
var visit = (node, testOrVisitor, visitor) => {
|
|
83
|
+
if (!visitor) {
|
|
84
|
+
visitNode(node, void 0, testOrVisitor);
|
|
85
|
+
} else {
|
|
86
|
+
visitNode(node, testOrVisitor, visitor);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
var visitNode = (node, test, visitor, path = [], depth = 0) => {
|
|
74
90
|
for (const prop of import_schema2.AST.getPropertySignatures(node)) {
|
|
75
91
|
const currentPath = [
|
|
76
92
|
...path,
|
|
@@ -78,45 +94,29 @@ var visitNode = (node, visitor, path = []) => {
|
|
|
78
94
|
];
|
|
79
95
|
const type = getType(prop.type);
|
|
80
96
|
if (type) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
const result = test?.(node, path, depth) ?? 0;
|
|
98
|
+
if (result === 2) {
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
visitor(type, currentPath, depth);
|
|
102
|
+
if (result !== 1) {
|
|
103
|
+
if (import_schema2.AST.isTypeLiteral(type)) {
|
|
104
|
+
visitNode(type, test, visitor, currentPath, depth + 1);
|
|
105
|
+
} else if (import_schema2.AST.isTupleType(type)) {
|
|
106
|
+
for (const [i, elementType] of type.elements.entries()) {
|
|
107
|
+
const type2 = getType(elementType.type);
|
|
108
|
+
if (type2) {
|
|
109
|
+
visitNode(type2, test, visitor, [
|
|
110
|
+
i,
|
|
111
|
+
...currentPath
|
|
112
|
+
], depth);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
87
115
|
}
|
|
88
116
|
}
|
|
89
117
|
}
|
|
90
118
|
}
|
|
91
119
|
};
|
|
92
|
-
var LOW_DASH = "_".codePointAt(0);
|
|
93
|
-
var SMALL_A = "a".codePointAt(0);
|
|
94
|
-
var CAPITAL_A = "A".codePointAt(0);
|
|
95
|
-
var SMALL_Z = "z".codePointAt(0);
|
|
96
|
-
var CAPITAL_Z = "Z".codePointAt(0);
|
|
97
|
-
var isLower = (char) => char >= SMALL_A && char <= SMALL_Z;
|
|
98
|
-
var isUpper = (char) => char >= CAPITAL_A && char <= CAPITAL_Z;
|
|
99
|
-
var toLower = (char) => char + 32;
|
|
100
|
-
var decamelize = (str) => {
|
|
101
|
-
const firstChar = str.charCodeAt(0);
|
|
102
|
-
if (!isLower(firstChar)) {
|
|
103
|
-
return str;
|
|
104
|
-
}
|
|
105
|
-
const length = str.length;
|
|
106
|
-
let changed = false;
|
|
107
|
-
const out = [];
|
|
108
|
-
for (let i = 0; i < length; ++i) {
|
|
109
|
-
const c = str.charCodeAt(i);
|
|
110
|
-
if (isUpper(c)) {
|
|
111
|
-
out.push(LOW_DASH);
|
|
112
|
-
out.push(toLower(c));
|
|
113
|
-
changed = true;
|
|
114
|
-
} else {
|
|
115
|
-
out.push(c);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return changed ? String.fromCharCode.apply(void 0, out) : str;
|
|
119
|
-
};
|
|
120
120
|
var ParamKeyAnnotationId = Symbol.for("@dxos/schema/annotation/ParamKey");
|
|
121
121
|
var getParamKeyAnnotation = import_schema3.AST.getAnnotation(ParamKeyAnnotationId);
|
|
122
122
|
var ParamKeyAnnotation = (value) => (self) => self.annotations({
|
|
@@ -132,7 +132,7 @@ var UrlParser = class {
|
|
|
132
132
|
parse(_url) {
|
|
133
133
|
const url = new URL(_url);
|
|
134
134
|
return Object.entries(this._schema.fields).reduce((params, [key, type]) => {
|
|
135
|
-
let value = url.searchParams.get(decamelize(key));
|
|
135
|
+
let value = url.searchParams.get((0, import_util.decamelize)(key));
|
|
136
136
|
if (value == null) {
|
|
137
137
|
value = url.searchParams.get(key);
|
|
138
138
|
}
|
|
@@ -158,7 +158,7 @@ var UrlParser = class {
|
|
|
158
158
|
const field = this._schema.fields[key];
|
|
159
159
|
if (field) {
|
|
160
160
|
const { key: serializedKey } = (0, import_effect2.pipe)(getParamKeyAnnotation(field.ast), import_effect2.Option.getOrElse(() => ({
|
|
161
|
-
key: decamelize(key)
|
|
161
|
+
key: (0, import_util.decamelize)(key)
|
|
162
162
|
})));
|
|
163
163
|
url.searchParams.set(serializedKey, String(value));
|
|
164
164
|
}
|
|
@@ -174,10 +174,12 @@ var UrlParser = class {
|
|
|
174
174
|
ParamKeyAnnotation,
|
|
175
175
|
S,
|
|
176
176
|
UrlParser,
|
|
177
|
+
VisitResult,
|
|
177
178
|
getAnnotation,
|
|
178
179
|
getParamKeyAnnotation,
|
|
179
180
|
getProperty,
|
|
180
181
|
getType,
|
|
182
|
+
isLeafType,
|
|
181
183
|
visit
|
|
182
184
|
});
|
|
183
185
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/ast.ts", "../../../src/url.ts"
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { AST, JSONSchema, Schema as S } from '@effect/schema';\nimport type * as Types from 'effect/Types';\n\nexport { AST, JSONSchema, S, Types };\n\nexport * from './ast';\nexport * from './url';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { invariant } from '@dxos/invariant';\n\n//\n// Refs\n// https://effect.website/docs/guides/schema\n// https://www.npmjs.com/package/@effect/schema\n// https://effect-ts.github.io/effect/schema/AST.ts.html\n//\n\n/**\n * Get annotation or return undefined.\n */\nexport const getAnnotation = <T>(annotationId: symbol, node: AST.Annotated): T | undefined =>\n pipe(AST.getAnnotation<T>(annotationId)(node), Option.getOrUndefined);\n\n/**\n * Get type node.\n */\nexport const getType = (node: AST.AST): AST.AST | undefined => {\n if (AST.isUnion(node)) {\n return node.types.find((type) => getType(type));\n } else if (AST.isRefinement(node)) {\n return getType(node.from);\n } else {\n return node;\n }\n};\n\n/**\n * Get the AST node for the given property (dot-path).\n */\nexport const getProperty = (schema: S.Schema<any>, path: string): AST.AST | undefined => {\n let node: AST.AST = schema.ast;\n for (const part of path.split('.')) {\n const props = AST.getPropertySignatures(node);\n const prop = props.find((prop) => prop.name === part);\n if (!prop) {\n return undefined;\n }\n\n // TODO(burdon): Check if leaf.\n const type = getType(prop.type);\n invariant(type, `invalid type: ${path}`);\n node = type;\n }\n\n return node;\n};\n\nexport type
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["import_schema", "import_effect", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/ast.ts", "../../../src/url.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { AST, JSONSchema, Schema as S } from '@effect/schema';\nimport type * as Types from 'effect/Types';\n\nexport { AST, JSONSchema, S, Types };\n\nexport * from './ast';\nexport * from './url';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { invariant } from '@dxos/invariant';\n\n//\n// Refs\n// https://effect.website/docs/guides/schema\n// https://www.npmjs.com/package/@effect/schema\n// https://effect-ts.github.io/effect/schema/AST.ts.html\n//\n\nexport const isLeafType = (node: AST.AST) => !AST.isTupleType(node) && !AST.isTypeLiteral(node);\n\n/**\n * Get annotation or return undefined.\n */\nexport const getAnnotation = <T>(annotationId: symbol, node: AST.Annotated): T | undefined =>\n pipe(AST.getAnnotation<T>(annotationId)(node), Option.getOrUndefined);\n\n/**\n * Get type node.\n */\nexport const getType = (node: AST.AST): AST.AST | undefined => {\n if (AST.isUnion(node)) {\n return node.types.find((type) => getType(type));\n } else if (AST.isRefinement(node)) {\n return getType(node.from);\n } else {\n return node;\n }\n};\n\n/**\n * Get the AST node for the given property (dot-path).\n */\nexport const getProperty = (schema: S.Schema<any>, path: string): AST.AST | undefined => {\n let node: AST.AST = schema.ast;\n for (const part of path.split('.')) {\n const props = AST.getPropertySignatures(node);\n const prop = props.find((prop) => prop.name === part);\n if (!prop) {\n return undefined;\n }\n\n // TODO(burdon): Check if leaf.\n const type = getType(prop.type);\n invariant(type, `invalid type: ${path}`);\n node = type;\n }\n\n return node;\n};\n\nexport enum VisitResult {\n CONTINUE = 0,\n /**\n * Skip visiting children.\n */\n SKIP = 1,\n /**\n * Stop traversing immeditaely.\n */\n EXIT = 2,\n}\n\nexport type Path = (string | number)[];\n\nexport type Tester = (node: AST.AST, path: Path, depth: number) => VisitResult;\nexport type Visitor = (node: AST.AST, path: Path, depth: number) => void;\n\n/**\n * Visit leaf nodes.\n * Refs:\n * - https://github.com/syntax-tree/unist-util-visit?tab=readme-ov-file#visitor\n * - https://github.com/syntax-tree/unist-util-is?tab=readme-ov-file#test\n */\nexport const visit: {\n (node: AST.AST, visitor: Visitor): void;\n (node: AST.AST, test: Tester, visitor: Visitor): void;\n} = (node: AST.AST, testOrVisitor: Tester | Visitor, visitor?: Visitor): void => {\n if (!visitor) {\n visitNode(node, undefined, testOrVisitor);\n } else {\n visitNode(node, testOrVisitor as Tester, visitor);\n }\n};\n\nconst visitNode = (\n node: AST.AST,\n test: Tester | undefined,\n visitor: Visitor,\n path: Path = [],\n depth = 0,\n): VisitResult | undefined => {\n for (const prop of AST.getPropertySignatures(node)) {\n const currentPath = [...path, prop.name.toString()];\n const type = getType(prop.type);\n if (type) {\n const result = test?.(node, path, depth) ?? VisitResult.CONTINUE;\n if (result === VisitResult.EXIT) {\n return result;\n }\n\n visitor(type, currentPath, depth);\n\n if (result !== VisitResult.SKIP) {\n if (AST.isTypeLiteral(type)) {\n visitNode(type, test, visitor, currentPath, depth + 1);\n } else if (AST.isTupleType(type)) {\n for (const [i, elementType] of type.elements.entries()) {\n const type = getType(elementType.type);\n if (type) {\n visitNode(type, test, visitor, [i, ...currentPath], depth);\n }\n }\n }\n }\n }\n }\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { decamelize } from '@dxos/util';\n\nconst ParamKeyAnnotationId = Symbol.for('@dxos/schema/annotation/ParamKey');\n\ntype ParamKeyAnnotationValue = { key: string };\n\nexport const getParamKeyAnnotation: (annotated: AST.Annotated) => Option.Option<ParamKeyAnnotationValue> =\n AST.getAnnotation<ParamKeyAnnotationValue>(ParamKeyAnnotationId);\n\nexport const ParamKeyAnnotation =\n (value: ParamKeyAnnotationValue) =>\n <S extends S.Annotable.All>(self: S): S.Annotable.Self<S> =>\n self.annotations({ [ParamKeyAnnotationId]: value });\n\n/**\n * HTTP params parser.\n * Supports custom key serialization.\n */\nexport class UrlParser<T extends Record<string, any>> {\n constructor(private readonly _schema: S.Struct<T>) {}\n\n /**\n * Parse URL params.\n */\n parse(_url: string): T {\n const url = new URL(_url);\n return Object.entries(this._schema.fields).reduce<Record<string, any>>((params, [key, type]) => {\n let value = url.searchParams.get(decamelize(key));\n if (value == null) {\n value = url.searchParams.get(key);\n }\n\n if (value != null) {\n if (AST.isNumberKeyword(type.ast)) {\n params[key] = parseInt(value);\n } else if (AST.isBooleanKeyword(type.ast)) {\n params[key] = value === 'true' || value === '1';\n } else {\n params[key] = value;\n }\n }\n\n return params;\n }, {}) as T;\n }\n\n /**\n * Return URL with encoded params.\n */\n create(_url: string, params: T): URL {\n const url = new URL(_url);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n const field = this._schema.fields[key];\n if (field) {\n const { key: serializedKey } = pipe(\n getParamKeyAnnotation(field.ast),\n Option.getOrElse(() => ({\n key: decamelize(key),\n })),\n );\n\n url.searchParams.set(serializedKey, String(value));\n }\n }\n });\n\n return url;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_schema", "import_effect", "isLeafType", "node", "AST", "isTupleType", "isTypeLiteral", "getAnnotation", "annotationId", "pipe", "Option", "getOrUndefined", "getType", "isUnion", "types", "find", "type", "isRefinement", "from", "getProperty", "schema", "path", "ast", "part", "split", "props", "getPropertySignatures", "prop", "name", "undefined", "invariant", "VisitResult", "visit", "testOrVisitor", "visitor", "visitNode", "test", "depth", "currentPath", "toString", "result", "i", "elementType", "elements", "entries", "ParamKeyAnnotationId", "Symbol", "for", "getParamKeyAnnotation", "ParamKeyAnnotation", "value", "self", "annotations", "UrlParser", "constructor", "_schema", "parse", "_url", "url", "URL", "Object", "fields", "reduce", "params", "key", "searchParams", "get", "decamelize", "isNumberKeyword", "parseInt", "isBooleanKeyword", "create", "forEach", "field", "serializedKey", "getOrElse", "set", "String"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/effect/src/ast.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/effect/src/ast.ts":{"bytes":11581,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true}],"format":"esm"},"packages/common/effect/src/url.ts":{"bytes":7711,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/common/effect/src/index.ts":{"bytes":1034,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"packages/common/effect/src/ast.ts","kind":"import-statement","original":"./ast"},{"path":"packages/common/effect/src/url.ts","kind":"import-statement","original":"./url"}],"format":"esm"}},"outputs":{"packages/common/effect/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":10201},"packages/common/effect/dist/lib/node/index.cjs":{"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["AST","JSONSchema","ParamKeyAnnotation","S","UrlParser","VisitResult","getAnnotation","getParamKeyAnnotation","getProperty","getType","isLeafType","visit"],"entryPoint":"packages/common/effect/src/index.ts","inputs":{"packages/common/effect/src/index.ts":{"bytesInOutput":71},"packages/common/effect/src/ast.ts":{"bytesInOutput":2437},"packages/common/effect/src/url.ts":{"bytesInOutput":1624}},"bytes":4468}}}
|
|
@@ -8,6 +8,7 @@ import { AST } from "@effect/schema";
|
|
|
8
8
|
import { Option, pipe } from "effect";
|
|
9
9
|
import { invariant } from "@dxos/invariant";
|
|
10
10
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/effect/src/ast.ts";
|
|
11
|
+
var isLeafType = (node) => !AST.isTupleType(node) && !AST.isTypeLiteral(node);
|
|
11
12
|
var getAnnotation = (annotationId, node) => pipe(AST.getAnnotation(annotationId)(node), Option.getOrUndefined);
|
|
12
13
|
var getType = (node) => {
|
|
13
14
|
if (AST.isUnion(node)) {
|
|
@@ -29,7 +30,7 @@ var getProperty = (schema, path) => {
|
|
|
29
30
|
const type = getType(prop.type);
|
|
30
31
|
invariant(type, `invalid type: ${path}`, {
|
|
31
32
|
F: __dxlog_file,
|
|
32
|
-
L:
|
|
33
|
+
L: 52,
|
|
33
34
|
S: void 0,
|
|
34
35
|
A: [
|
|
35
36
|
"type",
|
|
@@ -40,8 +41,20 @@ var getProperty = (schema, path) => {
|
|
|
40
41
|
}
|
|
41
42
|
return node;
|
|
42
43
|
};
|
|
43
|
-
var
|
|
44
|
-
|
|
44
|
+
var VisitResult;
|
|
45
|
+
(function(VisitResult2) {
|
|
46
|
+
VisitResult2[VisitResult2["CONTINUE"] = 0] = "CONTINUE";
|
|
47
|
+
VisitResult2[VisitResult2["SKIP"] = 1] = "SKIP";
|
|
48
|
+
VisitResult2[VisitResult2["EXIT"] = 2] = "EXIT";
|
|
49
|
+
})(VisitResult || (VisitResult = {}));
|
|
50
|
+
var visit = (node, testOrVisitor, visitor) => {
|
|
51
|
+
if (!visitor) {
|
|
52
|
+
visitNode(node, void 0, testOrVisitor);
|
|
53
|
+
} else {
|
|
54
|
+
visitNode(node, testOrVisitor, visitor);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var visitNode = (node, test, visitor, path = [], depth = 0) => {
|
|
45
58
|
for (const prop of AST.getPropertySignatures(node)) {
|
|
46
59
|
const currentPath = [
|
|
47
60
|
...path,
|
|
@@ -49,12 +62,24 @@ var visitNode = (node, visitor, path = []) => {
|
|
|
49
62
|
];
|
|
50
63
|
const type = getType(prop.type);
|
|
51
64
|
if (type) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
const result = test?.(node, path, depth) ?? 0;
|
|
66
|
+
if (result === 2) {
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
visitor(type, currentPath, depth);
|
|
70
|
+
if (result !== 1) {
|
|
71
|
+
if (AST.isTypeLiteral(type)) {
|
|
72
|
+
visitNode(type, test, visitor, currentPath, depth + 1);
|
|
73
|
+
} else if (AST.isTupleType(type)) {
|
|
74
|
+
for (const [i, elementType] of type.elements.entries()) {
|
|
75
|
+
const type2 = getType(elementType.type);
|
|
76
|
+
if (type2) {
|
|
77
|
+
visitNode(type2, test, visitor, [
|
|
78
|
+
i,
|
|
79
|
+
...currentPath
|
|
80
|
+
], depth);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
58
83
|
}
|
|
59
84
|
}
|
|
60
85
|
}
|
|
@@ -64,38 +89,7 @@ var visitNode = (node, visitor, path = []) => {
|
|
|
64
89
|
// packages/common/effect/src/url.ts
|
|
65
90
|
import { AST as AST2 } from "@effect/schema";
|
|
66
91
|
import { Option as Option2, pipe as pipe2 } from "effect";
|
|
67
|
-
|
|
68
|
-
// packages/common/effect/src/decamelize.ts
|
|
69
|
-
var LOW_DASH = "_".codePointAt(0);
|
|
70
|
-
var SMALL_A = "a".codePointAt(0);
|
|
71
|
-
var CAPITAL_A = "A".codePointAt(0);
|
|
72
|
-
var SMALL_Z = "z".codePointAt(0);
|
|
73
|
-
var CAPITAL_Z = "Z".codePointAt(0);
|
|
74
|
-
var isLower = (char) => char >= SMALL_A && char <= SMALL_Z;
|
|
75
|
-
var isUpper = (char) => char >= CAPITAL_A && char <= CAPITAL_Z;
|
|
76
|
-
var toLower = (char) => char + 32;
|
|
77
|
-
var decamelize = (str) => {
|
|
78
|
-
const firstChar = str.charCodeAt(0);
|
|
79
|
-
if (!isLower(firstChar)) {
|
|
80
|
-
return str;
|
|
81
|
-
}
|
|
82
|
-
const length = str.length;
|
|
83
|
-
let changed = false;
|
|
84
|
-
const out = [];
|
|
85
|
-
for (let i = 0; i < length; ++i) {
|
|
86
|
-
const c = str.charCodeAt(i);
|
|
87
|
-
if (isUpper(c)) {
|
|
88
|
-
out.push(LOW_DASH);
|
|
89
|
-
out.push(toLower(c));
|
|
90
|
-
changed = true;
|
|
91
|
-
} else {
|
|
92
|
-
out.push(c);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return changed ? String.fromCharCode.apply(void 0, out) : str;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// packages/common/effect/src/url.ts
|
|
92
|
+
import { decamelize } from "@dxos/util";
|
|
99
93
|
var ParamKeyAnnotationId = Symbol.for("@dxos/schema/annotation/ParamKey");
|
|
100
94
|
var getParamKeyAnnotation = AST2.getAnnotation(ParamKeyAnnotationId);
|
|
101
95
|
var ParamKeyAnnotation = (value) => (self) => self.annotations({
|
|
@@ -152,10 +146,12 @@ export {
|
|
|
152
146
|
ParamKeyAnnotation,
|
|
153
147
|
S,
|
|
154
148
|
UrlParser,
|
|
149
|
+
VisitResult,
|
|
155
150
|
getAnnotation,
|
|
156
151
|
getParamKeyAnnotation,
|
|
157
152
|
getProperty,
|
|
158
153
|
getType,
|
|
154
|
+
isLeafType,
|
|
159
155
|
visit
|
|
160
156
|
};
|
|
161
157
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/ast.ts", "../../../src/url.ts"
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { AST, JSONSchema, Schema as S } from '@effect/schema';\nimport type * as Types from 'effect/Types';\n\nexport { AST, JSONSchema, S, Types };\n\nexport * from './ast';\nexport * from './url';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { invariant } from '@dxos/invariant';\n\n//\n// Refs\n// https://effect.website/docs/guides/schema\n// https://www.npmjs.com/package/@effect/schema\n// https://effect-ts.github.io/effect/schema/AST.ts.html\n//\n\n/**\n * Get annotation or return undefined.\n */\nexport const getAnnotation = <T>(annotationId: symbol, node: AST.Annotated): T | undefined =>\n pipe(AST.getAnnotation<T>(annotationId)(node), Option.getOrUndefined);\n\n/**\n * Get type node.\n */\nexport const getType = (node: AST.AST): AST.AST | undefined => {\n if (AST.isUnion(node)) {\n return node.types.find((type) => getType(type));\n } else if (AST.isRefinement(node)) {\n return getType(node.from);\n } else {\n return node;\n }\n};\n\n/**\n * Get the AST node for the given property (dot-path).\n */\nexport const getProperty = (schema: S.Schema<any>, path: string): AST.AST | undefined => {\n let node: AST.AST = schema.ast;\n for (const part of path.split('.')) {\n const props = AST.getPropertySignatures(node);\n const prop = props.find((prop) => prop.name === part);\n if (!prop) {\n return undefined;\n }\n\n // TODO(burdon): Check if leaf.\n const type = getType(prop.type);\n invariant(type, `invalid type: ${path}`);\n node = type;\n }\n\n return node;\n};\n\nexport type
|
|
5
|
-
"mappings": ";;;AAIA,SAASA,OAAAA,MAAKC,YAAYC,UAAUC,SAAS;;;ACA7C,SAASC,WAA6B;AACtC,SAASC,QAAQC,YAAY;AAE7B,SAASC,iBAAiB;;
|
|
6
|
-
"names": ["AST", "JSONSchema", "Schema", "S", "AST", "Option", "pipe", "invariant", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/ast.ts", "../../../src/url.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2020 DXOS.org\n//\n\nimport { AST, JSONSchema, Schema as S } from '@effect/schema';\nimport type * as Types from 'effect/Types';\n\nexport { AST, JSONSchema, S, Types };\n\nexport * from './ast';\nexport * from './url';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { invariant } from '@dxos/invariant';\n\n//\n// Refs\n// https://effect.website/docs/guides/schema\n// https://www.npmjs.com/package/@effect/schema\n// https://effect-ts.github.io/effect/schema/AST.ts.html\n//\n\nexport const isLeafType = (node: AST.AST) => !AST.isTupleType(node) && !AST.isTypeLiteral(node);\n\n/**\n * Get annotation or return undefined.\n */\nexport const getAnnotation = <T>(annotationId: symbol, node: AST.Annotated): T | undefined =>\n pipe(AST.getAnnotation<T>(annotationId)(node), Option.getOrUndefined);\n\n/**\n * Get type node.\n */\nexport const getType = (node: AST.AST): AST.AST | undefined => {\n if (AST.isUnion(node)) {\n return node.types.find((type) => getType(type));\n } else if (AST.isRefinement(node)) {\n return getType(node.from);\n } else {\n return node;\n }\n};\n\n/**\n * Get the AST node for the given property (dot-path).\n */\nexport const getProperty = (schema: S.Schema<any>, path: string): AST.AST | undefined => {\n let node: AST.AST = schema.ast;\n for (const part of path.split('.')) {\n const props = AST.getPropertySignatures(node);\n const prop = props.find((prop) => prop.name === part);\n if (!prop) {\n return undefined;\n }\n\n // TODO(burdon): Check if leaf.\n const type = getType(prop.type);\n invariant(type, `invalid type: ${path}`);\n node = type;\n }\n\n return node;\n};\n\nexport enum VisitResult {\n CONTINUE = 0,\n /**\n * Skip visiting children.\n */\n SKIP = 1,\n /**\n * Stop traversing immeditaely.\n */\n EXIT = 2,\n}\n\nexport type Path = (string | number)[];\n\nexport type Tester = (node: AST.AST, path: Path, depth: number) => VisitResult;\nexport type Visitor = (node: AST.AST, path: Path, depth: number) => void;\n\n/**\n * Visit leaf nodes.\n * Refs:\n * - https://github.com/syntax-tree/unist-util-visit?tab=readme-ov-file#visitor\n * - https://github.com/syntax-tree/unist-util-is?tab=readme-ov-file#test\n */\nexport const visit: {\n (node: AST.AST, visitor: Visitor): void;\n (node: AST.AST, test: Tester, visitor: Visitor): void;\n} = (node: AST.AST, testOrVisitor: Tester | Visitor, visitor?: Visitor): void => {\n if (!visitor) {\n visitNode(node, undefined, testOrVisitor);\n } else {\n visitNode(node, testOrVisitor as Tester, visitor);\n }\n};\n\nconst visitNode = (\n node: AST.AST,\n test: Tester | undefined,\n visitor: Visitor,\n path: Path = [],\n depth = 0,\n): VisitResult | undefined => {\n for (const prop of AST.getPropertySignatures(node)) {\n const currentPath = [...path, prop.name.toString()];\n const type = getType(prop.type);\n if (type) {\n const result = test?.(node, path, depth) ?? VisitResult.CONTINUE;\n if (result === VisitResult.EXIT) {\n return result;\n }\n\n visitor(type, currentPath, depth);\n\n if (result !== VisitResult.SKIP) {\n if (AST.isTypeLiteral(type)) {\n visitNode(type, test, visitor, currentPath, depth + 1);\n } else if (AST.isTupleType(type)) {\n for (const [i, elementType] of type.elements.entries()) {\n const type = getType(elementType.type);\n if (type) {\n visitNode(type, test, visitor, [i, ...currentPath], depth);\n }\n }\n }\n }\n }\n }\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AST, type Schema as S } from '@effect/schema';\nimport { Option, pipe } from 'effect';\n\nimport { decamelize } from '@dxos/util';\n\nconst ParamKeyAnnotationId = Symbol.for('@dxos/schema/annotation/ParamKey');\n\ntype ParamKeyAnnotationValue = { key: string };\n\nexport const getParamKeyAnnotation: (annotated: AST.Annotated) => Option.Option<ParamKeyAnnotationValue> =\n AST.getAnnotation<ParamKeyAnnotationValue>(ParamKeyAnnotationId);\n\nexport const ParamKeyAnnotation =\n (value: ParamKeyAnnotationValue) =>\n <S extends S.Annotable.All>(self: S): S.Annotable.Self<S> =>\n self.annotations({ [ParamKeyAnnotationId]: value });\n\n/**\n * HTTP params parser.\n * Supports custom key serialization.\n */\nexport class UrlParser<T extends Record<string, any>> {\n constructor(private readonly _schema: S.Struct<T>) {}\n\n /**\n * Parse URL params.\n */\n parse(_url: string): T {\n const url = new URL(_url);\n return Object.entries(this._schema.fields).reduce<Record<string, any>>((params, [key, type]) => {\n let value = url.searchParams.get(decamelize(key));\n if (value == null) {\n value = url.searchParams.get(key);\n }\n\n if (value != null) {\n if (AST.isNumberKeyword(type.ast)) {\n params[key] = parseInt(value);\n } else if (AST.isBooleanKeyword(type.ast)) {\n params[key] = value === 'true' || value === '1';\n } else {\n params[key] = value;\n }\n }\n\n return params;\n }, {}) as T;\n }\n\n /**\n * Return URL with encoded params.\n */\n create(_url: string, params: T): URL {\n const url = new URL(_url);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n const field = this._schema.fields[key];\n if (field) {\n const { key: serializedKey } = pipe(\n getParamKeyAnnotation(field.ast),\n Option.getOrElse(() => ({\n key: decamelize(key),\n })),\n );\n\n url.searchParams.set(serializedKey, String(value));\n }\n }\n });\n\n return url;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["AST", "JSONSchema", "Schema", "S", "AST", "Option", "pipe", "invariant", "isLeafType", "node", "isTupleType", "isTypeLiteral", "getAnnotation", "annotationId", "getOrUndefined", "getType", "isUnion", "types", "find", "type", "isRefinement", "from", "getProperty", "schema", "path", "ast", "part", "split", "props", "getPropertySignatures", "prop", "name", "undefined", "VisitResult", "visit", "testOrVisitor", "visitor", "visitNode", "test", "depth", "currentPath", "toString", "result", "i", "elementType", "elements", "entries", "AST", "Option", "pipe", "decamelize", "ParamKeyAnnotationId", "Symbol", "for", "getParamKeyAnnotation", "AST", "getAnnotation", "ParamKeyAnnotation", "value", "self", "annotations", "UrlParser", "constructor", "_schema", "parse", "_url", "url", "URL", "Object", "entries", "fields", "reduce", "params", "key", "type", "searchParams", "get", "decamelize", "isNumberKeyword", "ast", "parseInt", "isBooleanKeyword", "create", "forEach", "undefined", "field", "serializedKey", "pipe", "Option", "getOrElse", "set", "String"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/effect/src/ast.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/effect/src/ast.ts":{"bytes":11581,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true}],"format":"esm"},"packages/common/effect/src/url.ts":{"bytes":7711,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/common/effect/src/index.ts":{"bytes":1034,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"packages/common/effect/src/ast.ts","kind":"import-statement","original":"./ast"},{"path":"packages/common/effect/src/url.ts","kind":"import-statement","original":"./url"}],"format":"esm"}},"outputs":{"packages/common/effect/dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":10203},"packages/common/effect/dist/lib/node-esm/index.mjs":{"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["AST","JSONSchema","ParamKeyAnnotation","S","UrlParser","VisitResult","getAnnotation","getParamKeyAnnotation","getProperty","getType","isLeafType","visit"],"entryPoint":"packages/common/effect/src/index.ts","inputs":{"packages/common/effect/src/index.ts":{"bytesInOutput":71},"packages/common/effect/src/ast.ts":{"bytesInOutput":2437},"packages/common/effect/src/url.ts":{"bytesInOutput":1624}},"bytes":4561}}}
|
package/dist/types/src/ast.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AST, type Schema as S } from '@effect/schema';
|
|
2
|
+
export declare const isLeafType: (node: AST.AST) => boolean;
|
|
2
3
|
/**
|
|
3
4
|
* Get annotation or return undefined.
|
|
4
5
|
*/
|
|
@@ -11,10 +12,28 @@ export declare const getType: (node: AST.AST) => AST.AST | undefined;
|
|
|
11
12
|
* Get the AST node for the given property (dot-path).
|
|
12
13
|
*/
|
|
13
14
|
export declare const getProperty: (schema: S.Schema<any>, path: string) => AST.AST | undefined;
|
|
14
|
-
export
|
|
15
|
+
export declare enum VisitResult {
|
|
16
|
+
CONTINUE = 0,
|
|
17
|
+
/**
|
|
18
|
+
* Skip visiting children.
|
|
19
|
+
*/
|
|
20
|
+
SKIP = 1,
|
|
21
|
+
/**
|
|
22
|
+
* Stop traversing immeditaely.
|
|
23
|
+
*/
|
|
24
|
+
EXIT = 2
|
|
25
|
+
}
|
|
26
|
+
export type Path = (string | number)[];
|
|
27
|
+
export type Tester = (node: AST.AST, path: Path, depth: number) => VisitResult;
|
|
28
|
+
export type Visitor = (node: AST.AST, path: Path, depth: number) => void;
|
|
15
29
|
/**
|
|
16
30
|
* Visit leaf nodes.
|
|
17
|
-
*
|
|
31
|
+
* Refs:
|
|
32
|
+
* - https://github.com/syntax-tree/unist-util-visit?tab=readme-ov-file#visitor
|
|
33
|
+
* - https://github.com/syntax-tree/unist-util-is?tab=readme-ov-file#test
|
|
18
34
|
*/
|
|
19
|
-
export declare const visit:
|
|
35
|
+
export declare const visit: {
|
|
36
|
+
(node: AST.AST, visitor: Visitor): void;
|
|
37
|
+
(node: AST.AST, test: Tester, visitor: Visitor): void;
|
|
38
|
+
};
|
|
20
39
|
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../src/ast.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,KAAK,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAYvD;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,gBAAgB,MAAM,QAAQ,GAAG,CAAC,SAAS,KAAG,CAAC,GAAG,SACV,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,OAAO,SAAU,GAAG,CAAC,GAAG,KAAG,GAAG,CAAC,GAAG,GAAG,SAQjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,WAAY,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,MAAM,KAAG,GAAG,CAAC,GAAG,GAAG,SAgB3E,CAAC;AAEF,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../src/ast.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,KAAK,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAYvD,eAAO,MAAM,UAAU,SAAU,GAAG,CAAC,GAAG,YAAuD,CAAC;AAEhG;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,gBAAgB,MAAM,QAAQ,GAAG,CAAC,SAAS,KAAG,CAAC,GAAG,SACV,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,OAAO,SAAU,GAAG,CAAC,GAAG,KAAG,GAAG,CAAC,GAAG,GAAG,SAQjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,WAAY,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,MAAM,KAAG,GAAG,CAAC,GAAG,GAAG,SAgB3E,CAAC;AAEF,oBAAY,WAAW;IACrB,QAAQ,IAAI;IACZ;;OAEG;IACH,IAAI,IAAI;IACR;;OAEG;IACH,IAAI,IAAI;CACT;AAED,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAEvC,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,WAAW,CAAC;AAC/E,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE;IAClB,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAOvD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/effect",
|
|
3
|
-
"version": "0.6.14-main.
|
|
3
|
+
"version": "0.6.14-main.69511f5",
|
|
4
4
|
"description": "Effect utils.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -8,12 +8,9 @@
|
|
|
8
8
|
"author": "info@dxos.org",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./dist/types/src/index.d.ts",
|
|
11
12
|
"browser": "./dist/lib/browser/index.mjs",
|
|
12
|
-
"node":
|
|
13
|
-
"require": "./dist/lib/node/index.cjs",
|
|
14
|
-
"default": "./dist/lib/node-esm/index.mjs"
|
|
15
|
-
},
|
|
16
|
-
"types": "./dist/types/src/index.d.ts"
|
|
13
|
+
"node": "./dist/lib/node-esm/index.mjs"
|
|
17
14
|
}
|
|
18
15
|
},
|
|
19
16
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -25,8 +22,9 @@
|
|
|
25
22
|
"src"
|
|
26
23
|
],
|
|
27
24
|
"dependencies": {
|
|
28
|
-
"@dxos/invariant": "0.6.14-main.
|
|
29
|
-
"@dxos/
|
|
25
|
+
"@dxos/invariant": "0.6.14-main.69511f5",
|
|
26
|
+
"@dxos/util": "0.6.14-main.69511f5",
|
|
27
|
+
"@dxos/node-std": "0.6.14-main.69511f5"
|
|
30
28
|
},
|
|
31
29
|
"devDependencies": {
|
|
32
30
|
"@effect/schema": "^0.75.1",
|
package/src/ast.test.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Schema as S } from '@effect/schema';
|
|
6
6
|
import { describe, expect, test } from 'vitest';
|
|
7
7
|
|
|
8
|
-
import { getProperty, visit } from './ast';
|
|
8
|
+
import { getProperty, isLeafType, visit } from './ast';
|
|
9
9
|
|
|
10
10
|
describe('AST', () => {
|
|
11
11
|
test('getProperty', () => {
|
|
@@ -30,9 +30,10 @@ describe('AST', () => {
|
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
test('
|
|
33
|
+
test('visit', () => {
|
|
34
34
|
const TestSchema = S.Struct({
|
|
35
35
|
name: S.optional(S.String),
|
|
36
|
+
emails: S.mutable(S.Array(S.String)),
|
|
36
37
|
address: S.optional(
|
|
37
38
|
S.Struct({
|
|
38
39
|
zip: S.String,
|
|
@@ -41,8 +42,10 @@ describe('AST', () => {
|
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
const props: string[] = [];
|
|
44
|
-
visit(TestSchema.ast, (
|
|
45
|
-
|
|
45
|
+
visit(TestSchema.ast, (node, path) => {
|
|
46
|
+
if (isLeafType(node)) {
|
|
47
|
+
props.push(path.join('.'));
|
|
48
|
+
}
|
|
46
49
|
});
|
|
47
50
|
expect(props).to.deep.eq(['name', 'address.zip']);
|
|
48
51
|
});
|
package/src/ast.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { invariant } from '@dxos/invariant';
|
|
|
14
14
|
// https://effect-ts.github.io/effect/schema/AST.ts.html
|
|
15
15
|
//
|
|
16
16
|
|
|
17
|
+
export const isLeafType = (node: AST.AST) => !AST.isTupleType(node) && !AST.isTypeLiteral(node);
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* Get annotation or return undefined.
|
|
19
21
|
*/
|
|
@@ -54,26 +56,68 @@ export const getProperty = (schema: S.Schema<any>, path: string): AST.AST | unde
|
|
|
54
56
|
return node;
|
|
55
57
|
};
|
|
56
58
|
|
|
57
|
-
export
|
|
59
|
+
export enum VisitResult {
|
|
60
|
+
CONTINUE = 0,
|
|
61
|
+
/**
|
|
62
|
+
* Skip visiting children.
|
|
63
|
+
*/
|
|
64
|
+
SKIP = 1,
|
|
65
|
+
/**
|
|
66
|
+
* Stop traversing immeditaely.
|
|
67
|
+
*/
|
|
68
|
+
EXIT = 2,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type Path = (string | number)[];
|
|
72
|
+
|
|
73
|
+
export type Tester = (node: AST.AST, path: Path, depth: number) => VisitResult;
|
|
74
|
+
export type Visitor = (node: AST.AST, path: Path, depth: number) => void;
|
|
58
75
|
|
|
59
76
|
/**
|
|
60
77
|
* Visit leaf nodes.
|
|
61
|
-
*
|
|
78
|
+
* Refs:
|
|
79
|
+
* - https://github.com/syntax-tree/unist-util-visit?tab=readme-ov-file#visitor
|
|
80
|
+
* - https://github.com/syntax-tree/unist-util-is?tab=readme-ov-file#test
|
|
62
81
|
*/
|
|
63
|
-
export const visit
|
|
82
|
+
export const visit: {
|
|
83
|
+
(node: AST.AST, visitor: Visitor): void;
|
|
84
|
+
(node: AST.AST, test: Tester, visitor: Visitor): void;
|
|
85
|
+
} = (node: AST.AST, testOrVisitor: Tester | Visitor, visitor?: Visitor): void => {
|
|
86
|
+
if (!visitor) {
|
|
87
|
+
visitNode(node, undefined, testOrVisitor);
|
|
88
|
+
} else {
|
|
89
|
+
visitNode(node, testOrVisitor as Tester, visitor);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
64
92
|
|
|
65
|
-
const visitNode = (
|
|
93
|
+
const visitNode = (
|
|
94
|
+
node: AST.AST,
|
|
95
|
+
test: Tester | undefined,
|
|
96
|
+
visitor: Visitor,
|
|
97
|
+
path: Path = [],
|
|
98
|
+
depth = 0,
|
|
99
|
+
): VisitResult | undefined => {
|
|
66
100
|
for (const prop of AST.getPropertySignatures(node)) {
|
|
67
101
|
const currentPath = [...path, prop.name.toString()];
|
|
68
102
|
const type = getType(prop.type);
|
|
69
103
|
if (type) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
104
|
+
const result = test?.(node, path, depth) ?? VisitResult.CONTINUE;
|
|
105
|
+
if (result === VisitResult.EXIT) {
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
visitor(type, currentPath, depth);
|
|
110
|
+
|
|
111
|
+
if (result !== VisitResult.SKIP) {
|
|
112
|
+
if (AST.isTypeLiteral(type)) {
|
|
113
|
+
visitNode(type, test, visitor, currentPath, depth + 1);
|
|
114
|
+
} else if (AST.isTupleType(type)) {
|
|
115
|
+
for (const [i, elementType] of type.elements.entries()) {
|
|
116
|
+
const type = getType(elementType.type);
|
|
117
|
+
if (type) {
|
|
118
|
+
visitNode(type, test, visitor, [i, ...currentPath], depth);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
77
121
|
}
|
|
78
122
|
}
|
|
79
123
|
}
|
package/src/url.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { AST, type Schema as S } from '@effect/schema';
|
|
6
6
|
import { Option, pipe } from 'effect';
|
|
7
7
|
|
|
8
|
-
import { decamelize } from '
|
|
8
|
+
import { decamelize } from '@dxos/util';
|
|
9
9
|
|
|
10
10
|
const ParamKeyAnnotationId = Symbol.for('@dxos/schema/annotation/ParamKey');
|
|
11
11
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decamelize.d.ts","sourceRoot":"","sources":["../../../src/decamelize.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,UAAU,QAAS,MAAM,WAmBrC,CAAC"}
|
package/src/decamelize.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
const LOW_DASH = '_'.codePointAt(0)!;
|
|
6
|
-
const SMALL_A = 'a'.codePointAt(0)!;
|
|
7
|
-
const CAPITAL_A = 'A'.codePointAt(0)!;
|
|
8
|
-
const SMALL_Z = 'z'.codePointAt(0)!;
|
|
9
|
-
const CAPITAL_Z = 'Z'.codePointAt(0)!;
|
|
10
|
-
|
|
11
|
-
const isLower = (char: number) => char >= SMALL_A && char <= SMALL_Z;
|
|
12
|
-
|
|
13
|
-
const isUpper = (char: number) => char >= CAPITAL_A && char <= CAPITAL_Z;
|
|
14
|
-
|
|
15
|
-
const toLower = (char: number) => char + 0x20;
|
|
16
|
-
|
|
17
|
-
export const decamelize = (str: string) => {
|
|
18
|
-
const firstChar = str.charCodeAt(0);
|
|
19
|
-
if (!isLower(firstChar)) {
|
|
20
|
-
return str;
|
|
21
|
-
}
|
|
22
|
-
const length = str.length;
|
|
23
|
-
let changed = false;
|
|
24
|
-
const out: number[] = [];
|
|
25
|
-
for (let i = 0; i < length; ++i) {
|
|
26
|
-
const c = str.charCodeAt(i);
|
|
27
|
-
if (isUpper(c)) {
|
|
28
|
-
out.push(LOW_DASH);
|
|
29
|
-
out.push(toLower(c));
|
|
30
|
-
changed = true;
|
|
31
|
-
} else {
|
|
32
|
-
out.push(c);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return changed ? String.fromCharCode.apply(undefined, out) : str;
|
|
36
|
-
};
|