@valbuild/react 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.
- package/package.json +10 -4
- package/.babelrc.json +0 -10
- package/CHANGELOG.md +0 -0
- package/jest-environment.mjs +0 -17
- package/jest.config.js +0 -5
- package/src/ShadowRoot.tsx +0 -42
- package/src/ValProvider.tsx +0 -48
- package/src/ValRichText.tsx +0 -198
- package/src/ValStore.ts +0 -110
- package/src/ValUI.tsx +0 -78
- package/src/assets.ts +0 -124
- package/src/index.ts +0 -3
- package/src/jsx-dev-runtime.js +0 -47
- package/src/jsx-namespace.d.ts +0 -46
- package/src/jsx-runtime.d.ts +0 -1
- package/src/jsx-runtime.dev.d.ts +0 -1
- package/src/jsx-runtime.js +0 -52
- package/src/stega/autoTagJSX.ts +0 -81
- package/src/stega/index.ts +0 -8
- package/src/stega/stegaEncode.test.ts +0 -154
- package/src/stega/stegaEncode.ts +0 -247
- package/tsconfig.json +0 -19
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@valbuild/react",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.27.0",
|
4
4
|
"private": false,
|
5
5
|
"description": "Val - React internal helpers",
|
6
6
|
"sideEffects": false,
|
@@ -9,8 +9,8 @@
|
|
9
9
|
"test": "jest"
|
10
10
|
},
|
11
11
|
"dependencies": {
|
12
|
-
"@valbuild/core": "~0.
|
13
|
-
"@valbuild/ui": "~0.
|
12
|
+
"@valbuild/core": "~0.27.0",
|
13
|
+
"@valbuild/ui": "~0.27.0",
|
14
14
|
"@vercel/stega": "^0.1.0",
|
15
15
|
"base64-arraybuffer": "^1.0.2",
|
16
16
|
"style-to-object": "^0.4.1"
|
@@ -88,5 +88,11 @@
|
|
88
88
|
},
|
89
89
|
"./package.json": "./package.json"
|
90
90
|
},
|
91
|
-
"types": "dist/valbuild-react.cjs.d.ts"
|
91
|
+
"types": "dist/valbuild-react.cjs.d.ts",
|
92
|
+
"files": [
|
93
|
+
"dist",
|
94
|
+
"jsx-runtime",
|
95
|
+
"jsx-dev-runtime",
|
96
|
+
"stega"
|
97
|
+
]
|
92
98
|
}
|
package/.babelrc.json
DELETED
package/CHANGELOG.md
DELETED
File without changes
|
package/jest-environment.mjs
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
import { TestEnvironment as JSDOMEnvironment } from "jest-environment-jsdom";
|
2
|
-
|
3
|
-
/**
|
4
|
-
* JSDOM currently does not support TextEncoder/TextDecoder...
|
5
|
-
* @see https://github.com/jsdom/jsdom/issues/2524
|
6
|
-
*/
|
7
|
-
class TestEnvironment extends JSDOMEnvironment {
|
8
|
-
async setup() {
|
9
|
-
await super.setup();
|
10
|
-
if (typeof this.global.TextEncoder === "undefined") {
|
11
|
-
this.global.TextEncoder = TextEncoder;
|
12
|
-
this.global.TextDecoder = TextDecoder;
|
13
|
-
}
|
14
|
-
}
|
15
|
-
}
|
16
|
-
|
17
|
-
export default TestEnvironment;
|
package/jest.config.js
DELETED
package/src/ShadowRoot.tsx
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
import { useState, useLayoutEffect, useRef, CSSProperties } from "react";
|
2
|
-
import { createPortal } from "react-dom";
|
3
|
-
|
4
|
-
function ShadowContent({
|
5
|
-
root,
|
6
|
-
children,
|
7
|
-
}: {
|
8
|
-
children: React.ReactNode;
|
9
|
-
root: Element | DocumentFragment;
|
10
|
-
}) {
|
11
|
-
return createPortal(children, root);
|
12
|
-
}
|
13
|
-
|
14
|
-
export const ShadowRoot = ({
|
15
|
-
children,
|
16
|
-
style,
|
17
|
-
}: {
|
18
|
-
children: React.ReactNode;
|
19
|
-
style?: CSSProperties;
|
20
|
-
}) => {
|
21
|
-
const node = useRef<HTMLDivElement>(null);
|
22
|
-
const [root, setRoot] = useState<ShadowRoot | null>(null);
|
23
|
-
|
24
|
-
useLayoutEffect(() => {
|
25
|
-
if (node.current) {
|
26
|
-
if (node.current.shadowRoot) {
|
27
|
-
setRoot(node.current.shadowRoot);
|
28
|
-
} else {
|
29
|
-
const root = node.current.attachShadow({
|
30
|
-
mode: "open",
|
31
|
-
});
|
32
|
-
setRoot(root);
|
33
|
-
}
|
34
|
-
}
|
35
|
-
}, []);
|
36
|
-
|
37
|
-
return (
|
38
|
-
<div ref={node} style={style} id="val-ui">
|
39
|
-
{root && <ShadowContent root={root}>{children}</ShadowContent>}
|
40
|
-
</div>
|
41
|
-
);
|
42
|
-
};
|
package/src/ValProvider.tsx
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
-
import React, { lazy, useContext, useMemo } from "react";
|
3
|
-
import { ValStore } from "./ValStore";
|
4
|
-
import { ValApi } from "@valbuild/core";
|
5
|
-
|
6
|
-
export function useValStore() {
|
7
|
-
return useContext(ValContext).valStore;
|
8
|
-
}
|
9
|
-
export function useValApi() {
|
10
|
-
return useContext(ValContext).valApi;
|
11
|
-
}
|
12
|
-
|
13
|
-
export type ValContext = {
|
14
|
-
readonly valStore: ValStore;
|
15
|
-
readonly valApi: ValApi;
|
16
|
-
};
|
17
|
-
|
18
|
-
export const ValContext = React.createContext<ValContext>({
|
19
|
-
get valStore(): never {
|
20
|
-
throw Error(
|
21
|
-
"Val context not found. Ensure components are wrapped by ValProvider!"
|
22
|
-
);
|
23
|
-
},
|
24
|
-
get valApi(): never {
|
25
|
-
throw Error(
|
26
|
-
"Val context not found. Ensure components are wrapped by ValProvider!"
|
27
|
-
);
|
28
|
-
},
|
29
|
-
});
|
30
|
-
|
31
|
-
export type ValProviderProps = {
|
32
|
-
// host?: string;
|
33
|
-
children?: React.ReactNode;
|
34
|
-
};
|
35
|
-
const ValUI =
|
36
|
-
typeof window !== "undefined" ? lazy(() => import("./ValUI")) : null;
|
37
|
-
|
38
|
-
export function ValProvider({ children }: ValProviderProps) {
|
39
|
-
const host = "/api/val";
|
40
|
-
const valApi = useMemo(() => new ValApi(host), [host]);
|
41
|
-
const valStore = useMemo(() => new ValStore(valApi), [valApi]);
|
42
|
-
return (
|
43
|
-
<ValContext.Provider value={{ valApi, valStore }}>
|
44
|
-
{children}
|
45
|
-
{ValUI && <ValUI />}
|
46
|
-
</ValContext.Provider>
|
47
|
-
);
|
48
|
-
}
|
package/src/ValRichText.tsx
DELETED
@@ -1,198 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/ban-types */
|
2
|
-
import {
|
3
|
-
RichText,
|
4
|
-
RichTextNode,
|
5
|
-
AnyRichTextOptions,
|
6
|
-
SourcePath,
|
7
|
-
RichTextOptions,
|
8
|
-
} from "@valbuild/core";
|
9
|
-
import React from "react";
|
10
|
-
|
11
|
-
// Pick is used to make sure we do not add a tag or class that is not in options:
|
12
|
-
type Tags = keyof Pick<RichTextOptions, "img" | "ul" | "ol">;
|
13
|
-
type Classes = keyof Pick<RichTextOptions, "bold" | "italic" | "lineThrough">;
|
14
|
-
|
15
|
-
type ThemeOptions<O extends RichTextOptions> = {
|
16
|
-
tags: (O["headings"] extends Array<unknown>
|
17
|
-
? {
|
18
|
-
[Key in O["headings"][number]]: string;
|
19
|
-
}
|
20
|
-
: {}) & {
|
21
|
-
[Key in Tags & keyof O as O[Key] extends true
|
22
|
-
? Key extends "ul" | "ol"
|
23
|
-
? Key | "li"
|
24
|
-
: Key
|
25
|
-
: never]: string;
|
26
|
-
} & { p?: string };
|
27
|
-
classes: {
|
28
|
-
[Key in Classes & keyof O as O[Key] extends true ? Key : never]: string;
|
29
|
-
};
|
30
|
-
};
|
31
|
-
|
32
|
-
export function ValRichText<O extends RichTextOptions>({
|
33
|
-
theme,
|
34
|
-
children,
|
35
|
-
}: {
|
36
|
-
theme: ThemeOptions<O>;
|
37
|
-
children: RichText<O>;
|
38
|
-
}) {
|
39
|
-
const root = children as RichText<AnyRichTextOptions> & {
|
40
|
-
valPath: SourcePath;
|
41
|
-
};
|
42
|
-
function withRenderTag(
|
43
|
-
clazz: keyof ThemeOptions<AnyRichTextOptions>["tags"],
|
44
|
-
current?: string
|
45
|
-
) {
|
46
|
-
const renderClass = (theme as ThemeOptions<AnyRichTextOptions>).tags[clazz];
|
47
|
-
if (renderClass && current) {
|
48
|
-
return [current, renderClass].join(" ");
|
49
|
-
}
|
50
|
-
if (renderClass) {
|
51
|
-
return renderClass;
|
52
|
-
}
|
53
|
-
return current;
|
54
|
-
}
|
55
|
-
function withRenderClass(
|
56
|
-
clazz: keyof ThemeOptions<AnyRichTextOptions>["classes"],
|
57
|
-
current?: string
|
58
|
-
) {
|
59
|
-
const renderClass = (theme as ThemeOptions<AnyRichTextOptions>).classes[
|
60
|
-
clazz
|
61
|
-
];
|
62
|
-
if (renderClass && current) {
|
63
|
-
return [current, renderClass].join(" ");
|
64
|
-
}
|
65
|
-
if (renderClass) {
|
66
|
-
return renderClass;
|
67
|
-
}
|
68
|
-
return current;
|
69
|
-
}
|
70
|
-
|
71
|
-
function toReact(
|
72
|
-
node: RichTextNode<AnyRichTextOptions>,
|
73
|
-
key: number | string
|
74
|
-
): React.ReactNode {
|
75
|
-
if (typeof node === "string") {
|
76
|
-
return node;
|
77
|
-
}
|
78
|
-
if (node.tag === "p") {
|
79
|
-
return (
|
80
|
-
<p className={withRenderTag("p")} key={key}>
|
81
|
-
{node.children.map(toReact)}
|
82
|
-
</p>
|
83
|
-
);
|
84
|
-
}
|
85
|
-
if (node.tag === "img") {
|
86
|
-
return <img className={withRenderTag("img")} key={key} src={node.src} />;
|
87
|
-
}
|
88
|
-
if (node.tag === "ul") {
|
89
|
-
return (
|
90
|
-
<ul className={withRenderTag("ul")} key={key}>
|
91
|
-
{node.children.map(toReact)}
|
92
|
-
</ul>
|
93
|
-
);
|
94
|
-
}
|
95
|
-
if (node.tag === "ol") {
|
96
|
-
return (
|
97
|
-
<ol className={withRenderTag("ol")} key={key}>
|
98
|
-
{node.children.map(toReact)}
|
99
|
-
</ol>
|
100
|
-
);
|
101
|
-
}
|
102
|
-
if (node.tag === "li") {
|
103
|
-
return (
|
104
|
-
<li className={withRenderTag("li")} key={key}>
|
105
|
-
{node.children.map(toReact)}
|
106
|
-
</li>
|
107
|
-
);
|
108
|
-
}
|
109
|
-
if (node.tag === "span") {
|
110
|
-
return (
|
111
|
-
<span
|
112
|
-
key={key}
|
113
|
-
className={node.classes
|
114
|
-
.map((nodeClass) => {
|
115
|
-
switch (nodeClass) {
|
116
|
-
case "bold":
|
117
|
-
return withRenderClass("bold");
|
118
|
-
case "line-through":
|
119
|
-
return withRenderClass("lineThrough");
|
120
|
-
case "italic":
|
121
|
-
return withRenderClass("italic");
|
122
|
-
}
|
123
|
-
})
|
124
|
-
.join(" ")}
|
125
|
-
>
|
126
|
-
{node.children.map(toReact)}
|
127
|
-
</span>
|
128
|
-
);
|
129
|
-
}
|
130
|
-
if (node.tag === "h1") {
|
131
|
-
return (
|
132
|
-
<h1 className={withRenderTag("h1")} key={key}>
|
133
|
-
{node.children.map(toReact)}
|
134
|
-
</h1>
|
135
|
-
);
|
136
|
-
}
|
137
|
-
if (node.tag === "h2") {
|
138
|
-
return (
|
139
|
-
<h2 className={withRenderTag("h2")} key={key}>
|
140
|
-
{node.children.map(toReact)}
|
141
|
-
</h2>
|
142
|
-
);
|
143
|
-
}
|
144
|
-
if (node.tag === "h3") {
|
145
|
-
return (
|
146
|
-
<h3 className={withRenderTag("h3")} key={key}>
|
147
|
-
{node.children.map(toReact)}
|
148
|
-
</h3>
|
149
|
-
);
|
150
|
-
}
|
151
|
-
if (node.tag === "h4") {
|
152
|
-
return (
|
153
|
-
<h4 className={withRenderTag("h4")} key={key}>
|
154
|
-
{node.children.map(toReact)}
|
155
|
-
</h4>
|
156
|
-
);
|
157
|
-
}
|
158
|
-
if (node.tag === "h5") {
|
159
|
-
return (
|
160
|
-
<h5 className={withRenderTag("h5")} key={key}>
|
161
|
-
{node.children.map(toReact)}
|
162
|
-
</h5>
|
163
|
-
);
|
164
|
-
}
|
165
|
-
if (node.tag === "h6") {
|
166
|
-
return (
|
167
|
-
<h6 className={withRenderTag("h6")} key={key}>
|
168
|
-
{node.children.map(toReact)}
|
169
|
-
</h6>
|
170
|
-
);
|
171
|
-
}
|
172
|
-
|
173
|
-
if (node.tag === "br") {
|
174
|
-
return <br key={key} />;
|
175
|
-
}
|
176
|
-
if (node.tag === "a") {
|
177
|
-
return (
|
178
|
-
<a href={node.href} key={key}>
|
179
|
-
{node.children.map(toReact)}
|
180
|
-
</a>
|
181
|
-
);
|
182
|
-
}
|
183
|
-
console.error("Unknown tag", node.tag);
|
184
|
-
const _exhaustiveCheck: never = node.tag;
|
185
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
186
|
-
const anyNode = _exhaustiveCheck as any;
|
187
|
-
if (!anyNode?.tag) {
|
188
|
-
return null;
|
189
|
-
}
|
190
|
-
return React.createElement(anyNode.tag, {
|
191
|
-
key,
|
192
|
-
className: anyNode.class?.join(" "),
|
193
|
-
children: anyNode.children?.map(toReact),
|
194
|
-
});
|
195
|
-
}
|
196
|
-
|
197
|
-
return <div data-val-path={root.valPath}>{root.children.map(toReact)}</div>;
|
198
|
-
}
|
package/src/ValStore.ts
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
import { Json, ModuleId, ValApi } from "@valbuild/core";
|
2
|
-
import { result } from "@valbuild/core/fp";
|
3
|
-
import { IValStore } from "@valbuild/ui";
|
4
|
-
|
5
|
-
type SubscriberId = string & {
|
6
|
-
readonly _tag: unique symbol;
|
7
|
-
};
|
8
|
-
|
9
|
-
export class ValStore implements IValStore {
|
10
|
-
private readonly subscribers: Map<SubscriberId, Record<ModuleId, Json>>; // uncertain whether this is the optimal way of returning
|
11
|
-
private readonly listeners: Record<SubscriberId, (() => void)[]>;
|
12
|
-
|
13
|
-
constructor(private readonly api: ValApi) {
|
14
|
-
this.subscribers = new Map();
|
15
|
-
this.listeners = {};
|
16
|
-
}
|
17
|
-
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
19
|
-
async update(moduleIds: ModuleId[]) {
|
20
|
-
// TODO: update only the modules that have changed
|
21
|
-
return this.updateAll();
|
22
|
-
}
|
23
|
-
|
24
|
-
async updateAll() {
|
25
|
-
const data = await this.api.getModules({
|
26
|
-
patch: true,
|
27
|
-
includeSource: true,
|
28
|
-
});
|
29
|
-
if (result.isOk(data)) {
|
30
|
-
const updatedSubscriberIds = new Map<SubscriberId, ModuleId[]>();
|
31
|
-
const subscriberIds = Array.from(this.subscribers.keys());
|
32
|
-
|
33
|
-
// Figure out which modules have been updated and map to updated subscribed id
|
34
|
-
for (const moduleId of Object.keys(data.value.modules) as ModuleId[]) {
|
35
|
-
const source = data.value.modules[moduleId].source;
|
36
|
-
if (typeof source !== "undefined") {
|
37
|
-
const updatedSubscriberId = subscriberIds.find(
|
38
|
-
(subscriberId) => subscriberId.includes(moduleId) // NOTE: dependent on
|
39
|
-
);
|
40
|
-
if (updatedSubscriberId) {
|
41
|
-
updatedSubscriberIds.set(
|
42
|
-
updatedSubscriberId,
|
43
|
-
(updatedSubscriberIds.get(updatedSubscriberId) || []).concat(
|
44
|
-
moduleId
|
45
|
-
)
|
46
|
-
);
|
47
|
-
}
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
// For all updated subscribers: set new module data and emit change
|
52
|
-
for (const [updatedSubscriberId, moduleIds] of Array.from(
|
53
|
-
updatedSubscriberIds.entries()
|
54
|
-
)) {
|
55
|
-
const subscriberModules = Object.fromEntries(
|
56
|
-
moduleIds.flatMap((moduleId) => {
|
57
|
-
const source = data.value.modules[moduleId].source;
|
58
|
-
if (!source) {
|
59
|
-
return [];
|
60
|
-
}
|
61
|
-
return [[moduleId, source]];
|
62
|
-
})
|
63
|
-
);
|
64
|
-
this.subscribers.set(updatedSubscriberId, subscriberModules);
|
65
|
-
this.emitChange(updatedSubscriberId);
|
66
|
-
}
|
67
|
-
} else {
|
68
|
-
console.error("Val: failed to update modules", data.error.message);
|
69
|
-
}
|
70
|
-
}
|
71
|
-
|
72
|
-
subscribe = (moduleIds: ModuleId[]) => (listener: () => void) => {
|
73
|
-
const subscriberId = createSubscriberId(moduleIds);
|
74
|
-
if (!this.listeners[subscriberId]) {
|
75
|
-
this.listeners[subscriberId] = [];
|
76
|
-
this.subscribers.set(subscriberId, {});
|
77
|
-
}
|
78
|
-
this.listeners[subscriberId].push(listener);
|
79
|
-
|
80
|
-
return () => {
|
81
|
-
this.listeners[subscriberId].splice(
|
82
|
-
this.listeners[subscriberId].indexOf(listener),
|
83
|
-
1
|
84
|
-
);
|
85
|
-
};
|
86
|
-
};
|
87
|
-
|
88
|
-
private emitChange(subscriberId: SubscriberId) {
|
89
|
-
for (const listener of this.listeners[subscriberId]) {
|
90
|
-
listener();
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
getSnapshot = (moduleIds: ModuleId[]) => () => {
|
95
|
-
return this.get(moduleIds);
|
96
|
-
};
|
97
|
-
|
98
|
-
getServerSnapshot = (moduleIds: ModuleId[]) => () => {
|
99
|
-
return this.get(moduleIds);
|
100
|
-
};
|
101
|
-
|
102
|
-
get = (moduleIds: ModuleId[]): Record<ModuleId, Json> | undefined => {
|
103
|
-
const subscriberId = createSubscriberId(moduleIds);
|
104
|
-
return this.subscribers.get(subscriberId);
|
105
|
-
};
|
106
|
-
}
|
107
|
-
|
108
|
-
function createSubscriberId(moduleIds: ModuleId[]): SubscriberId {
|
109
|
-
return moduleIds.slice().sort().join("&") as SubscriberId;
|
110
|
-
}
|
package/src/ValUI.tsx
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
"use client";
|
2
|
-
|
3
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
4
|
-
import { Internal } from "@valbuild/core";
|
5
|
-
import { Style, ValOverlay } from "@valbuild/ui";
|
6
|
-
import { useEffect, useState } from "react";
|
7
|
-
import { ShadowRoot } from "./ShadowRoot";
|
8
|
-
import { useValApi, useValStore } from "./ValProvider";
|
9
|
-
|
10
|
-
export default function ValUI() {
|
11
|
-
const [isClient, setIsClient] = useState(false);
|
12
|
-
const [enabled, setEnabled] = useState(false);
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
14
|
-
const [isDraftMode, setDraftMode] = useState(false); // TODO: if enabled, but not in draft mode: show something
|
15
|
-
const api = useValApi();
|
16
|
-
const store = useValStore();
|
17
|
-
useEffect(() => {
|
18
|
-
setIsClient(true);
|
19
|
-
try {
|
20
|
-
const valEnabled = document.cookie?.includes(
|
21
|
-
`${Internal.VAL_ENABLE_COOKIE_NAME}=true`
|
22
|
-
);
|
23
|
-
setEnabled(valEnabled);
|
24
|
-
} catch (e) {
|
25
|
-
console.warn("Could not read Val enabled state", e);
|
26
|
-
}
|
27
|
-
try {
|
28
|
-
const valDraftMode = document.cookie?.includes(
|
29
|
-
`${Internal.VAL_DRAFT_MODE_COOKIE}=true`
|
30
|
-
);
|
31
|
-
setDraftMode(valDraftMode);
|
32
|
-
} catch (e) {
|
33
|
-
console.warn("Could not read Val draft mode", e);
|
34
|
-
}
|
35
|
-
}, []);
|
36
|
-
if (isClient && !enabled && process.env.NODE_ENV === "development") {
|
37
|
-
console.log(
|
38
|
-
`Val is disabled. Enable it by going here ${window.origin}${
|
39
|
-
api.host
|
40
|
-
}/enable?redirect_to=${encodeURIComponent(
|
41
|
-
window.location.href
|
42
|
-
)}. NOTE: this message appears because NODE_ENV is set to development.`
|
43
|
-
);
|
44
|
-
}
|
45
|
-
if (!isClient || !enabled) {
|
46
|
-
return null;
|
47
|
-
}
|
48
|
-
return (
|
49
|
-
<>
|
50
|
-
<ShadowRoot
|
51
|
-
style={{
|
52
|
-
position: "absolute",
|
53
|
-
top: 0,
|
54
|
-
left: 0,
|
55
|
-
zIndex: 8999, // 1 less than the NextJS error z-index: 9000
|
56
|
-
}}
|
57
|
-
>
|
58
|
-
{/* TODO: */}
|
59
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
60
|
-
<link
|
61
|
-
rel="preconnect"
|
62
|
-
href="https://fonts.gstatic.com"
|
63
|
-
crossOrigin="anonymous"
|
64
|
-
/>
|
65
|
-
<link
|
66
|
-
href="https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap"
|
67
|
-
rel="stylesheet"
|
68
|
-
/>
|
69
|
-
<link
|
70
|
-
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;1,100;1,300;1,400;1,500;1,700&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap"
|
71
|
-
rel="stylesheet"
|
72
|
-
/>
|
73
|
-
<Style />
|
74
|
-
<ValOverlay api={api} store={store} />
|
75
|
-
</ShadowRoot>
|
76
|
-
</>
|
77
|
-
);
|
78
|
-
}
|
package/src/assets.ts
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
import * as base64 from "base64-arraybuffer";
|
2
|
-
|
3
|
-
function dataUrl(mimeType: string, data: string): string {
|
4
|
-
return `data:${mimeType};base64,${base64.encode(
|
5
|
-
new TextEncoder().encode(data)
|
6
|
-
)}`;
|
7
|
-
}
|
8
|
-
|
9
|
-
// TODO: stroke should be currentColor
|
10
|
-
export const editIcon = (size: number, stroke: string) =>
|
11
|
-
dataUrl(
|
12
|
-
"image/svg+xml",
|
13
|
-
`
|
14
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="${stroke}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
|
15
|
-
`
|
16
|
-
);
|
17
|
-
|
18
|
-
export const logo = dataUrl(
|
19
|
-
"image/svg+xml",
|
20
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
21
|
-
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
22
|
-
|
23
|
-
<svg
|
24
|
-
width="101.83195mm"
|
25
|
-
height="103.55328mm"
|
26
|
-
viewBox="0 0 101.83195 103.55328"
|
27
|
-
version="1.1"
|
28
|
-
id="svg974"
|
29
|
-
inkscape:export-filename="logo.svg"
|
30
|
-
inkscape:export-xdpi="96"
|
31
|
-
inkscape:export-ydpi="96"
|
32
|
-
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
33
|
-
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
34
|
-
xmlns="http://www.w3.org/2000/svg"
|
35
|
-
xmlns:svg="http://www.w3.org/2000/svg">
|
36
|
-
<sodipodi:namedview
|
37
|
-
id="namedview976"
|
38
|
-
pagecolor="#ffffff"
|
39
|
-
bordercolor="#000000"
|
40
|
-
borderopacity="0.25"
|
41
|
-
inkscape:showpageshadow="2"
|
42
|
-
inkscape:pageopacity="0.0"
|
43
|
-
inkscape:pagecheckerboard="0"
|
44
|
-
inkscape:deskcolor="#d1d1d1"
|
45
|
-
inkscape:document-units="mm"
|
46
|
-
showgrid="false"
|
47
|
-
inkscape:zoom="1.4040232"
|
48
|
-
inkscape:cx="39.173141"
|
49
|
-
inkscape:cy="503.90904"
|
50
|
-
inkscape:window-width="3832"
|
51
|
-
inkscape:window-height="2087"
|
52
|
-
inkscape:window-x="0"
|
53
|
-
inkscape:window-y="69"
|
54
|
-
inkscape:window-maximized="1"
|
55
|
-
inkscape:current-layer="layer1" />
|
56
|
-
<defs
|
57
|
-
id="defs971" />
|
58
|
-
<g
|
59
|
-
inkscape:label="Layer 1"
|
60
|
-
inkscape:groupmode="layer"
|
61
|
-
id="layer1"
|
62
|
-
transform="translate(-46.162121,-16.863144)">
|
63
|
-
<ellipse
|
64
|
-
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:4.41854;stroke-dasharray:none;stroke-opacity:1"
|
65
|
-
id="path2242"
|
66
|
-
ry="49.567371"
|
67
|
-
rx="48.706703"
|
68
|
-
cy="68.639786"
|
69
|
-
cx="97.078094" />
|
70
|
-
<path
|
71
|
-
style="fill:#000000;fill-opacity:1;stroke:#f2f2f2;stroke-width:9.9912;stroke-dasharray:none;stroke-opacity:1"
|
72
|
-
d="m 65.105895,44.462411 18.85692,45.934668 13.064363,-39.90188 15.829132,39.947835 23.07956,-0.1822"
|
73
|
-
id="path4245"
|
74
|
-
sodipodi:nodetypes="ccccc" />
|
75
|
-
<path
|
76
|
-
style="fill:#000000;fill-opacity:1;stroke:#f2f2f2;stroke-width:4.85097;stroke-dasharray:none;stroke-opacity:1"
|
77
|
-
d="M 108.18755,79.963752 C 101.58768,84.940963 94.021144,82.50121 86.406627,79.693345"
|
78
|
-
id="path4249"
|
79
|
-
sodipodi:nodetypes="cc" />
|
80
|
-
</g>
|
81
|
-
</svg>`
|
82
|
-
);
|
83
|
-
|
84
|
-
export const valcmsLogo = dataUrl(
|
85
|
-
"image/svg+xml",
|
86
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
87
|
-
<svg
|
88
|
-
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
89
|
-
xmlns:cc="http://creativecommons.org/ns#"
|
90
|
-
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
91
|
-
xmlns:svg="http://www.w3.org/2000/svg"
|
92
|
-
xmlns="http://www.w3.org/2000/svg"
|
93
|
-
width="20"
|
94
|
-
height="20"
|
95
|
-
viewBox="0 0 52.916665 52.916668"
|
96
|
-
version="1.1"
|
97
|
-
id="svg8">
|
98
|
-
<defs
|
99
|
-
id="defs2" />
|
100
|
-
<metadata
|
101
|
-
id="metadata5">
|
102
|
-
<rdf:RDF>
|
103
|
-
<cc:Work
|
104
|
-
rdf:about="">
|
105
|
-
<dc:format>image/svg+xml</dc:format>
|
106
|
-
<dc:type
|
107
|
-
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
108
|
-
<dc:title></dc:title>
|
109
|
-
</cc:Work>
|
110
|
-
</rdf:RDF>
|
111
|
-
</metadata>
|
112
|
-
<g
|
113
|
-
id="layer1">
|
114
|
-
<path
|
115
|
-
style="fill:none;stroke:white;stroke-width:5.00377;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
116
|
-
d="M 3.9337727,9.883415 14.718441,43.556958 25.597715,9.9678121 35.530965,43.388176 h 15.798599 v 0 h 0.09461"
|
117
|
-
id="path10" />
|
118
|
-
<path
|
119
|
-
style="fill:none;stroke:white;stroke-width:5.00377;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
120
|
-
d="m 19.826972,27.859518 11.257682,0.0844 v 0 0"
|
121
|
-
id="path837" />
|
122
|
-
</g>
|
123
|
-
</svg>`
|
124
|
-
);
|
package/src/index.ts
DELETED
package/src/jsx-dev-runtime.js
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
import { Internal } from "@valbuild/core";
|
2
|
-
import * as ReactJSXRuntimeDev from "react/jsx-dev-runtime";
|
3
|
-
export * from "react/jsx-dev-runtime";
|
4
|
-
|
5
|
-
const isIntrinsicElement = (type) => {
|
6
|
-
// TODO: think this is not correct, but good enough for now?
|
7
|
-
return typeof type === "string";
|
8
|
-
};
|
9
|
-
|
10
|
-
const devalProps = (type, props) => {
|
11
|
-
const valSources = [];
|
12
|
-
|
13
|
-
if (isIntrinsicElement(type)) {
|
14
|
-
for (const [key, value] of Object.entries(props)) {
|
15
|
-
if (typeof value === "object" && value !== null && "val" in value) {
|
16
|
-
const valPath = Internal.getValPath(value);
|
17
|
-
if (valPath) {
|
18
|
-
valSources.push(valPath);
|
19
|
-
if (typeof value.val === "string" || value.val === null) {
|
20
|
-
props[key] = value.val;
|
21
|
-
} else {
|
22
|
-
throw Error("TODO: unhandled value type");
|
23
|
-
}
|
24
|
-
}
|
25
|
-
}
|
26
|
-
}
|
27
|
-
}
|
28
|
-
|
29
|
-
if (valSources.length > 0) {
|
30
|
-
props["data-val-path"] = valSources.join(",");
|
31
|
-
}
|
32
|
-
};
|
33
|
-
|
34
|
-
export function jsxDEV(type, props, key, isStaticChildren, source, self) {
|
35
|
-
// console.log("jsxDEV", type, props, key, isStaticChildren, source, self);
|
36
|
-
|
37
|
-
devalProps(type, props);
|
38
|
-
|
39
|
-
return ReactJSXRuntimeDev.jsxDEV(
|
40
|
-
type,
|
41
|
-
props,
|
42
|
-
key,
|
43
|
-
isStaticChildren,
|
44
|
-
source,
|
45
|
-
self
|
46
|
-
);
|
47
|
-
}
|
package/src/jsx-namespace.d.ts
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
import { Source, Val } from "@valbuild/core";
|
2
|
-
|
3
|
-
// unpack all here to avoid infinite self-referencing when defining our own JSX namespace
|
4
|
-
type ReactJSXElement = JSX.Element;
|
5
|
-
type ReactJSXElementClass = JSX.ElementClass;
|
6
|
-
type ReactJSXElementAttributesProperty = JSX.ElementAttributesProperty;
|
7
|
-
type ReactJSXElementChildrenAttribute = JSX.ElementChildrenAttribute;
|
8
|
-
type ReactJSXLibraryManagedAttributes<C, P> = JSX.LibraryManagedAttributes<
|
9
|
-
C,
|
10
|
-
P
|
11
|
-
>;
|
12
|
-
type ReactJSXIntrinsicAttributes = JSX.IntrinsicAttributes;
|
13
|
-
type ReactJSXIntrinsicClassAttributes<T> = JSX.IntrinsicClassAttributes<T>;
|
14
|
-
type ReactJSXIntrinsicElements = JSX.IntrinsicElements;
|
15
|
-
|
16
|
-
type MaybeVal<T> = T extends Source ? Val<T> | T : T;
|
17
|
-
type WithVal<T extends object> = {
|
18
|
-
[K in keyof T]: K extends "key" | "ref" | "className"
|
19
|
-
? T[K]
|
20
|
-
: K extends "style"
|
21
|
-
? WithVal<React.CSSProperties>
|
22
|
-
: T[K] extends object
|
23
|
-
? T[K]
|
24
|
-
: MaybeVal<T[K]>;
|
25
|
-
};
|
26
|
-
|
27
|
-
export namespace ValJSX {
|
28
|
-
export type Element = ReactJSXElement;
|
29
|
-
export type ElementClass = ReactJSXElementClass;
|
30
|
-
export type ElementAttributesProperty = ReactJSXElementAttributesProperty;
|
31
|
-
export type ElementChildrenAttribute = ReactJSXElementChildrenAttribute;
|
32
|
-
|
33
|
-
export type LibraryManagedAttributes<C, P> = ReactJSXLibraryManagedAttributes<
|
34
|
-
C,
|
35
|
-
P
|
36
|
-
>;
|
37
|
-
|
38
|
-
export type IntrinsicAttributes = ReactJSXIntrinsicAttributes;
|
39
|
-
export type IntrinsicClassAttributes<T> = ReactJSXIntrinsicClassAttributes<T>;
|
40
|
-
|
41
|
-
export type IntrinsicElements = {
|
42
|
-
[K in keyof ReactJSXIntrinsicElements]: WithVal<
|
43
|
-
ReactJSXIntrinsicElements[K]
|
44
|
-
>;
|
45
|
-
};
|
46
|
-
}
|
package/src/jsx-runtime.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export { ValJSX as JSX } from "./jsx-namespace";
|
package/src/jsx-runtime.dev.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export { ValJSX as JSX } from "./jsx-namespace";
|
package/src/jsx-runtime.js
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
import { Internal } from "@valbuild/core";
|
2
|
-
import * as ReactJSXRuntime from "react/jsx-runtime";
|
3
|
-
export * from "react/jsx-runtime";
|
4
|
-
|
5
|
-
const isIntrinsicElement = (type) => {
|
6
|
-
// TODO: think this is not correct, but good enough for now?
|
7
|
-
return typeof type === "string";
|
8
|
-
};
|
9
|
-
|
10
|
-
const devalProps = (type, props) => {
|
11
|
-
const valSources = [];
|
12
|
-
|
13
|
-
if (isIntrinsicElement(type)) {
|
14
|
-
for (const [key, value] of Object.entries(props)) {
|
15
|
-
if (typeof value === "object" && value !== null && "val" in value) {
|
16
|
-
const valPath = Internal.getValPath(value);
|
17
|
-
if (valPath) {
|
18
|
-
valSources.push(valPath);
|
19
|
-
if (typeof value.val === "string" || value.val === null) {
|
20
|
-
props[key] = value.val;
|
21
|
-
} else {
|
22
|
-
throw Error("TODO: unhandled value type");
|
23
|
-
}
|
24
|
-
}
|
25
|
-
}
|
26
|
-
}
|
27
|
-
}
|
28
|
-
|
29
|
-
if (valSources.length > 0) {
|
30
|
-
props["data-val-path"] = valSources.join(",");
|
31
|
-
}
|
32
|
-
};
|
33
|
-
|
34
|
-
export function jsx(type, props, key) {
|
35
|
-
// console.log("jsx", type, props, key);
|
36
|
-
|
37
|
-
devalProps(type, props);
|
38
|
-
|
39
|
-
return ReactJSXRuntime.jsx(type, props, key);
|
40
|
-
}
|
41
|
-
|
42
|
-
export function jsxs(type, props, key) {
|
43
|
-
// console.log("jsxs", type, props, key);
|
44
|
-
|
45
|
-
if (key === "key") {
|
46
|
-
console.log("jsxDEV", type, props, key, self);
|
47
|
-
}
|
48
|
-
|
49
|
-
devalProps(type, props);
|
50
|
-
|
51
|
-
return ReactJSXRuntime.jsxs(type, props, key);
|
52
|
-
}
|
package/src/stega/autoTagJSX.ts
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
-
import jsxRuntime from "react/jsx-runtime";
|
3
|
-
import jsxRuntimeDev from "react/jsx-dev-runtime";
|
4
|
-
import React from "react";
|
5
|
-
import {
|
6
|
-
vercelStegaSplit,
|
7
|
-
vercelStegaDecode,
|
8
|
-
VERCEL_STEGA_REGEX,
|
9
|
-
} from "@vercel/stega";
|
10
|
-
|
11
|
-
const isIntrinsicElement = (type: any) => {
|
12
|
-
// TODO: think this is not correct, but good enough for now?
|
13
|
-
return typeof type === "string";
|
14
|
-
};
|
15
|
-
|
16
|
-
const addValPathIfFound = (type: any, props: any) => {
|
17
|
-
const valSources: any = [];
|
18
|
-
if (props && typeof props === "object") {
|
19
|
-
for (const [key, value] of Object.entries(props)) {
|
20
|
-
if (typeof value === "string" && value.match(VERCEL_STEGA_REGEX)) {
|
21
|
-
const encodedBits = vercelStegaDecode(value);
|
22
|
-
if (!encodedBits || typeof encodedBits !== "object") continue;
|
23
|
-
if (
|
24
|
-
"origin" in encodedBits &&
|
25
|
-
"data" in encodedBits &&
|
26
|
-
typeof encodedBits.data === "object" &&
|
27
|
-
encodedBits.data &&
|
28
|
-
"valPath" in encodedBits.data
|
29
|
-
) {
|
30
|
-
const valPath = encodedBits?.data?.valPath;
|
31
|
-
if (valPath) {
|
32
|
-
valSources.push(valPath);
|
33
|
-
props[key] = isIntrinsicElement(type)
|
34
|
-
? vercelStegaSplit(value).cleaned
|
35
|
-
: value;
|
36
|
-
props[`data-val-attr-${key}`] = valPath;
|
37
|
-
}
|
38
|
-
}
|
39
|
-
}
|
40
|
-
}
|
41
|
-
|
42
|
-
if (valSources.length > 0) {
|
43
|
-
props["data-val-path"] = valSources.join(",");
|
44
|
-
}
|
45
|
-
}
|
46
|
-
};
|
47
|
-
|
48
|
-
function WrapJsx<T>(jsx: T): T {
|
49
|
-
if (typeof jsx !== "function") return jsx;
|
50
|
-
|
51
|
-
return function (type: any, props: any, ...rest: any[]) {
|
52
|
-
addValPathIfFound(type, props);
|
53
|
-
return jsx.call(jsx, type, props, ...rest);
|
54
|
-
} as any as T;
|
55
|
-
}
|
56
|
-
|
57
|
-
interface JsxRuntimeModule {
|
58
|
-
jsx?(type: any, ...rest: any[]): unknown;
|
59
|
-
jsxs?(type: any, ...rest: any[]): unknown;
|
60
|
-
jsxDEV?(type: any, ...rest: any[]): unknown;
|
61
|
-
}
|
62
|
-
|
63
|
-
export function autoTagJSX() {
|
64
|
-
const JsxPro: JsxRuntimeModule = jsxRuntime;
|
65
|
-
const JsxDev: JsxRuntimeModule = jsxRuntimeDev;
|
66
|
-
|
67
|
-
/**
|
68
|
-
* createElement _may_ be called by jsx runtime as a fallback in certain cases,
|
69
|
-
* so we need to wrap it regardless.
|
70
|
-
*
|
71
|
-
* The jsx exports depend on the `NODE_ENV` var to ensure the users' bundler doesn't
|
72
|
-
* include both, so one of them will be set with `undefined` values.
|
73
|
-
*/
|
74
|
-
React.createElement = WrapJsx(React.createElement);
|
75
|
-
JsxDev.jsx && /* */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));
|
76
|
-
JsxPro.jsx && /* */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));
|
77
|
-
JsxDev.jsxs && /* */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));
|
78
|
-
JsxPro.jsxs && /* */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));
|
79
|
-
JsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));
|
80
|
-
JsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));
|
81
|
-
}
|
package/src/stega/index.ts
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
import { getModuleIds, stegaEncode } from "./stegaEncode";
|
2
|
-
import { initVal } from "@valbuild/core";
|
3
|
-
import { vercelStegaDecode, vercelStegaSplit } from "@vercel/stega";
|
4
|
-
|
5
|
-
const { s, val } = initVal();
|
6
|
-
|
7
|
-
describe("stega transform", () => {
|
8
|
-
test("basic", () => {
|
9
|
-
const schema = s.array(
|
10
|
-
s.object({
|
11
|
-
image: s.image(),
|
12
|
-
text: s.richtext({}),
|
13
|
-
n: s.number(),
|
14
|
-
b: s.boolean(),
|
15
|
-
})
|
16
|
-
);
|
17
|
-
|
18
|
-
const valModule = val.content("/test", schema, [
|
19
|
-
{
|
20
|
-
image: val.file("/public/test1.png", {
|
21
|
-
sha256: "1231",
|
22
|
-
width: 100,
|
23
|
-
height: 100,
|
24
|
-
}),
|
25
|
-
text: val.richtext`Test`,
|
26
|
-
n: 1,
|
27
|
-
b: true,
|
28
|
-
},
|
29
|
-
{
|
30
|
-
image: val.file("/public/test2.png", {
|
31
|
-
sha256: "1232",
|
32
|
-
width: 100,
|
33
|
-
height: 100,
|
34
|
-
}),
|
35
|
-
text: val.richtext`Test`,
|
36
|
-
n: 2,
|
37
|
-
b: false,
|
38
|
-
},
|
39
|
-
]);
|
40
|
-
const transformed = stegaEncode(valModule, {});
|
41
|
-
|
42
|
-
expect(transformed).toHaveLength(2);
|
43
|
-
|
44
|
-
expect(vercelStegaDecode(transformed[0].image.url)).toStrictEqual({
|
45
|
-
data: {
|
46
|
-
valPath: '/test.0."image"',
|
47
|
-
},
|
48
|
-
origin: "val.build",
|
49
|
-
});
|
50
|
-
expect(vercelStegaDecode(transformed[1].image.url)).toStrictEqual({
|
51
|
-
data: {
|
52
|
-
valPath: '/test.1."image"',
|
53
|
-
},
|
54
|
-
origin: "val.build",
|
55
|
-
});
|
56
|
-
//
|
57
|
-
expect(vercelStegaSplit(transformed[0].image.url).cleaned).toStrictEqual(
|
58
|
-
"/test1.png?sha256=1231"
|
59
|
-
);
|
60
|
-
expect(vercelStegaSplit(transformed[1].image.url).cleaned).toStrictEqual(
|
61
|
-
"/test2.png?sha256=1232"
|
62
|
-
);
|
63
|
-
|
64
|
-
expect(transformed[0].text.valPath).toStrictEqual('/test.0."text"');
|
65
|
-
expect(transformed[1].text.valPath).toStrictEqual('/test.1."text"');
|
66
|
-
});
|
67
|
-
|
68
|
-
test("get modules", () => {
|
69
|
-
const schema = s.array(s.string());
|
70
|
-
|
71
|
-
expect(
|
72
|
-
getModuleIds({
|
73
|
-
foo: [
|
74
|
-
{ test: val.content("/test1", schema, ["one", "two"]) },
|
75
|
-
{ test: val.content("/test2", schema, ["one", "two"]) },
|
76
|
-
],
|
77
|
-
test: val.content("/test3", schema, ["one", "two"]),
|
78
|
-
})
|
79
|
-
).toStrictEqual(["/test1", "/test2", "/test3"]);
|
80
|
-
});
|
81
|
-
|
82
|
-
test("basic transform with get modules", () => {
|
83
|
-
const schema = s.array(s.string());
|
84
|
-
const transformed = stegaEncode(
|
85
|
-
val.content("/test1", schema, ["one", "two"]),
|
86
|
-
{
|
87
|
-
getModule: (moduleId) => {
|
88
|
-
if (moduleId === "/test1") {
|
89
|
-
return ["1", "2"];
|
90
|
-
}
|
91
|
-
},
|
92
|
-
}
|
93
|
-
);
|
94
|
-
|
95
|
-
expect(vercelStegaSplit(transformed[0]).cleaned).toStrictEqual("1");
|
96
|
-
expect(vercelStegaDecode(transformed[0])).toStrictEqual({
|
97
|
-
data: {
|
98
|
-
valPath: "/test1.0",
|
99
|
-
},
|
100
|
-
origin: "val.build",
|
101
|
-
});
|
102
|
-
});
|
103
|
-
|
104
|
-
test("Dont stegaEncode raw strings schema", () => {
|
105
|
-
const schema = s.object({ str: s.string(), rawStr: s.string().raw() });
|
106
|
-
const transformed = stegaEncode(
|
107
|
-
val.content("/test1", schema, { str: "one", rawStr: "two" }),
|
108
|
-
{}
|
109
|
-
);
|
110
|
-
//expect(transformed.str).toStrictEqual("one");
|
111
|
-
expect(transformed.rawStr).toStrictEqual("two");
|
112
|
-
});
|
113
|
-
test("transform with get modules", () => {
|
114
|
-
const schema = s.array(s.string());
|
115
|
-
const transformed = stegaEncode(
|
116
|
-
{
|
117
|
-
foo: [
|
118
|
-
{ test: val.content("/test1", schema, ["one", "two"]) },
|
119
|
-
{ test: val.content("/test2", schema, ["one", "two"]) },
|
120
|
-
],
|
121
|
-
test: val.content("/test3", schema, ["one", "two"]),
|
122
|
-
},
|
123
|
-
{
|
124
|
-
getModule: (moduleId) => {
|
125
|
-
if (moduleId === "/test2") {
|
126
|
-
return ["1", "2"];
|
127
|
-
}
|
128
|
-
},
|
129
|
-
}
|
130
|
-
);
|
131
|
-
|
132
|
-
expect(vercelStegaSplit(transformed.foo[0].test[0]).cleaned).toStrictEqual(
|
133
|
-
"one"
|
134
|
-
);
|
135
|
-
expect(vercelStegaDecode(transformed.foo[0].test[0])).toStrictEqual({
|
136
|
-
data: {
|
137
|
-
valPath: "/test1.0",
|
138
|
-
},
|
139
|
-
origin: "val.build",
|
140
|
-
});
|
141
|
-
|
142
|
-
//
|
143
|
-
|
144
|
-
expect(vercelStegaSplit(transformed.foo[1].test[0]).cleaned).toStrictEqual(
|
145
|
-
"1"
|
146
|
-
);
|
147
|
-
expect(vercelStegaDecode(transformed.foo[1].test[0])).toStrictEqual({
|
148
|
-
data: {
|
149
|
-
valPath: "/test2.0",
|
150
|
-
},
|
151
|
-
origin: "val.build",
|
152
|
-
});
|
153
|
-
});
|
154
|
-
});
|
package/src/stega/stegaEncode.ts
DELETED
@@ -1,247 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
-
import {
|
3
|
-
Json,
|
4
|
-
Internal,
|
5
|
-
RichTextSource,
|
6
|
-
RichText,
|
7
|
-
VAL_EXTENSION,
|
8
|
-
FILE_REF_PROP,
|
9
|
-
} from "@valbuild/core";
|
10
|
-
import { vercelStegaCombine } from "@vercel/stega";
|
11
|
-
import { FileSource, Source, SourceObject } from "@valbuild/core";
|
12
|
-
import { JsonPrimitive } from "@valbuild/core";
|
13
|
-
import { SourceArray } from "@valbuild/core";
|
14
|
-
import { parseRichTextSource } from "@valbuild/ui";
|
15
|
-
import { RawString } from "@valbuild/core/src/schema/string";
|
16
|
-
|
17
|
-
declare const brand: unique symbol;
|
18
|
-
|
19
|
-
/**
|
20
|
-
* ValEncodedString is a string that is encoded using steganography.
|
21
|
-
*
|
22
|
-
* This means that there is a hidden / non-visible object embedded in the string.
|
23
|
-
* This object includes a path, which is used to automatically tag
|
24
|
-
* where the content comes from for contextual editing.
|
25
|
-
*
|
26
|
-
*/
|
27
|
-
export type ValEncodedString = string & {
|
28
|
-
[brand]: "ValEncodedString";
|
29
|
-
};
|
30
|
-
|
31
|
-
export type StegaOfSource<T extends Source> = Json extends T
|
32
|
-
? Json
|
33
|
-
: T extends RichTextSource<infer O>
|
34
|
-
? RichText<O>
|
35
|
-
: T extends FileSource
|
36
|
-
? { url: ValEncodedString }
|
37
|
-
: T extends SourceObject
|
38
|
-
? {
|
39
|
-
[key in keyof T]: StegaOfSource<T[key]>;
|
40
|
-
}
|
41
|
-
: T extends SourceArray
|
42
|
-
? StegaOfSource<T[number]>[]
|
43
|
-
: T extends RawString
|
44
|
-
? string
|
45
|
-
: T extends string
|
46
|
-
? ValEncodedString
|
47
|
-
: T extends JsonPrimitive
|
48
|
-
? T
|
49
|
-
: never;
|
50
|
-
|
51
|
-
export function stegaEncode(
|
52
|
-
input: any,
|
53
|
-
opts: {
|
54
|
-
getModule?: (moduleId: string) => any;
|
55
|
-
disabled?: boolean;
|
56
|
-
}
|
57
|
-
): any {
|
58
|
-
function rec(
|
59
|
-
sourceOrSelector: any,
|
60
|
-
recOpts?: { path: any; schema: any }
|
61
|
-
): any {
|
62
|
-
if (typeof sourceOrSelector === "object") {
|
63
|
-
if (!sourceOrSelector) {
|
64
|
-
return null;
|
65
|
-
}
|
66
|
-
const selectorPath = Internal.getValPath(sourceOrSelector);
|
67
|
-
if (selectorPath) {
|
68
|
-
const newSchema = Internal.getSchema(sourceOrSelector);
|
69
|
-
return rec(
|
70
|
-
(opts.getModule && opts.getModule(selectorPath)) ||
|
71
|
-
Internal.getSource(sourceOrSelector),
|
72
|
-
opts.disabled ? undefined : { path: selectorPath, schema: newSchema }
|
73
|
-
);
|
74
|
-
}
|
75
|
-
|
76
|
-
if (VAL_EXTENSION in sourceOrSelector) {
|
77
|
-
if (sourceOrSelector[VAL_EXTENSION] === "richtext") {
|
78
|
-
if (recOpts?.path) {
|
79
|
-
return {
|
80
|
-
...parseRichTextSource(sourceOrSelector),
|
81
|
-
valPath: recOpts.path,
|
82
|
-
};
|
83
|
-
}
|
84
|
-
|
85
|
-
return parseRichTextSource(sourceOrSelector);
|
86
|
-
}
|
87
|
-
|
88
|
-
if (
|
89
|
-
sourceOrSelector[VAL_EXTENSION] === "file" &&
|
90
|
-
typeof sourceOrSelector[FILE_REF_PROP] === "string"
|
91
|
-
) {
|
92
|
-
const fileSelector = Internal.convertFileSource(sourceOrSelector);
|
93
|
-
return {
|
94
|
-
...fileSelector,
|
95
|
-
url: rec(fileSelector.url, recOpts),
|
96
|
-
};
|
97
|
-
}
|
98
|
-
console.error(
|
99
|
-
`Encountered unexpected extension: ${sourceOrSelector[VAL_EXTENSION]}`
|
100
|
-
);
|
101
|
-
return sourceOrSelector;
|
102
|
-
}
|
103
|
-
|
104
|
-
if (Array.isArray(sourceOrSelector)) {
|
105
|
-
return sourceOrSelector.map((el, i) =>
|
106
|
-
rec(
|
107
|
-
el,
|
108
|
-
recOpts && {
|
109
|
-
path: Internal.createValPathOfItem(recOpts.path, i),
|
110
|
-
schema: recOpts.schema.item,
|
111
|
-
}
|
112
|
-
)
|
113
|
-
);
|
114
|
-
}
|
115
|
-
|
116
|
-
if (!Array.isArray(sourceOrSelector)) {
|
117
|
-
const res: Record<string, any> = {};
|
118
|
-
for (const [key, value] of Object.entries(sourceOrSelector)) {
|
119
|
-
res[key] = rec(
|
120
|
-
value,
|
121
|
-
recOpts && {
|
122
|
-
path: Internal.createValPathOfItem(recOpts.path, key),
|
123
|
-
schema:
|
124
|
-
recOpts.schema.item || // Record
|
125
|
-
recOpts.schema.items[key], // Object
|
126
|
-
}
|
127
|
-
);
|
128
|
-
}
|
129
|
-
return res;
|
130
|
-
}
|
131
|
-
|
132
|
-
console.error(
|
133
|
-
`Could not transform source selector: ${typeof sourceOrSelector} (array: ${Array.isArray(
|
134
|
-
sourceOrSelector
|
135
|
-
)})`,
|
136
|
-
sourceOrSelector
|
137
|
-
);
|
138
|
-
return sourceOrSelector;
|
139
|
-
}
|
140
|
-
|
141
|
-
if (typeof sourceOrSelector === "string") {
|
142
|
-
if (!recOpts) {
|
143
|
-
return sourceOrSelector;
|
144
|
-
}
|
145
|
-
if (recOpts.schema.isRaw) {
|
146
|
-
return sourceOrSelector;
|
147
|
-
}
|
148
|
-
return vercelStegaCombine(
|
149
|
-
sourceOrSelector,
|
150
|
-
{
|
151
|
-
origin: "val.build",
|
152
|
-
data: { valPath: recOpts.path },
|
153
|
-
},
|
154
|
-
false // auto detection on urls and dates is disabled, isDate could be used but it is also disabled (users should use a date schema instead): isDate(sourceOrSelector) // skip = true if isDate
|
155
|
-
);
|
156
|
-
}
|
157
|
-
|
158
|
-
if (
|
159
|
-
typeof sourceOrSelector === "number" ||
|
160
|
-
typeof sourceOrSelector === "boolean"
|
161
|
-
) {
|
162
|
-
return sourceOrSelector;
|
163
|
-
}
|
164
|
-
|
165
|
-
console.error(
|
166
|
-
`Unexpected type of source selector: ${typeof sourceOrSelector}`
|
167
|
-
);
|
168
|
-
return sourceOrSelector;
|
169
|
-
}
|
170
|
-
return rec(input);
|
171
|
-
}
|
172
|
-
|
173
|
-
export function getModuleIds(input: any): string[] {
|
174
|
-
const modules: Set<string> = new Set();
|
175
|
-
function rec(sourceOrSelector: any): undefined {
|
176
|
-
if (typeof sourceOrSelector === "object") {
|
177
|
-
if (!sourceOrSelector) {
|
178
|
-
return;
|
179
|
-
}
|
180
|
-
const selectorPath = Internal.getValPath(sourceOrSelector);
|
181
|
-
if (selectorPath) {
|
182
|
-
modules.add(selectorPath);
|
183
|
-
return;
|
184
|
-
}
|
185
|
-
|
186
|
-
if (VAL_EXTENSION in sourceOrSelector) {
|
187
|
-
if (sourceOrSelector[VAL_EXTENSION] === "richtext") {
|
188
|
-
return;
|
189
|
-
}
|
190
|
-
|
191
|
-
if (
|
192
|
-
sourceOrSelector[VAL_EXTENSION] === "file" &&
|
193
|
-
typeof sourceOrSelector[FILE_REF_PROP] === "string"
|
194
|
-
) {
|
195
|
-
return;
|
196
|
-
}
|
197
|
-
console.error(
|
198
|
-
`Encountered unexpected extension: ${sourceOrSelector[VAL_EXTENSION]}`
|
199
|
-
);
|
200
|
-
return sourceOrSelector;
|
201
|
-
}
|
202
|
-
|
203
|
-
if (Array.isArray(sourceOrSelector)) {
|
204
|
-
sourceOrSelector.forEach(rec);
|
205
|
-
return;
|
206
|
-
}
|
207
|
-
|
208
|
-
if (!Array.isArray(sourceOrSelector)) {
|
209
|
-
for (const [, value] of Object.entries(sourceOrSelector)) {
|
210
|
-
rec(value);
|
211
|
-
}
|
212
|
-
return;
|
213
|
-
}
|
214
|
-
|
215
|
-
console.error(
|
216
|
-
`Could not transform source selector: ${typeof sourceOrSelector} (array: ${Array.isArray(
|
217
|
-
sourceOrSelector
|
218
|
-
)})`,
|
219
|
-
sourceOrSelector
|
220
|
-
);
|
221
|
-
return;
|
222
|
-
}
|
223
|
-
|
224
|
-
if (typeof sourceOrSelector === "string") {
|
225
|
-
return;
|
226
|
-
}
|
227
|
-
|
228
|
-
if (
|
229
|
-
typeof sourceOrSelector === "number" ||
|
230
|
-
typeof sourceOrSelector === "boolean"
|
231
|
-
) {
|
232
|
-
return;
|
233
|
-
}
|
234
|
-
|
235
|
-
console.error(
|
236
|
-
`Unexpected type of source selector: ${typeof sourceOrSelector}`
|
237
|
-
);
|
238
|
-
return;
|
239
|
-
}
|
240
|
-
rec(input);
|
241
|
-
return Array.from(modules);
|
242
|
-
}
|
243
|
-
|
244
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
245
|
-
function isDate(s: string) {
|
246
|
-
return Boolean(Date.parse(s));
|
247
|
-
}
|
package/tsconfig.json
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"compilerOptions": {
|
3
|
-
"esModuleInterop": true,
|
4
|
-
"strict": true,
|
5
|
-
"allowJs": true,
|
6
|
-
"isolatedModules": true,
|
7
|
-
"jsx": "react-jsx",
|
8
|
-
"jsxImportSource": "@valbuild/react",
|
9
|
-
"lib": ["es6", "dom"],
|
10
|
-
"module": "CommonJS",
|
11
|
-
"noEmit": true,
|
12
|
-
"target": "ES5",
|
13
|
-
"outDir": "dist",
|
14
|
-
"rootDir": "src",
|
15
|
-
"skipLibCheck": true
|
16
|
-
},
|
17
|
-
"include": ["src/**/*"],
|
18
|
-
"exclude": ["dist/**", "jsx-runtime/dist/**", "jsx-dev-runtime/dist/**"]
|
19
|
-
}
|