jinrai 1.1.2 → 1.1.3
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/index.ts +2 -0
- package/lib/bin/bin.js +8 -7
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/src/bin/agent/agent.d.ts +1 -0
- package/lib/src/bin/agent/agent.js +3 -0
- package/lib/src/bin/routes/Parser.d.ts +6 -1
- package/lib/src/bin/routes/Parser.js +5 -0
- package/lib/src/front/server-state/DataProxy.d.ts +2 -1
- package/lib/src/front/server-state/DataProxy.js +119 -60
- package/lib/src/front/server-state/SSR.d.ts +2 -0
- package/lib/src/front/server-state/SSR.js +16 -3
- package/lib/src/front/server-state/real.js +15 -1
- package/lib/src/front/server-state/serverStates.d.ts +2 -1
- package/lib/src/front/server-state/serverStates.js +19 -16
- package/lib/src/front/server-state/useServerState.d.ts +1 -1
- package/lib/src/front/server-state/useServerState.js +10 -10
- package/lib/src/front/url/params/useParamsIndex.js +2 -1
- package/lib/src/front/url/search/useSearch.js +2 -1
- package/lib/src/front/url/search/useSearchValue.d.ts +11 -5
- package/lib/src/front/url/search/useSearchValue.js +13 -8
- package/lib/src/front/wrapper/Custom.d.ts +3 -3
- package/lib/src/front/wrapper/Custom.js +14 -1
- package/lib/vite/plugin.js +15 -149
- package/package.json +5 -1
- package/src/bin/agent/agent.ts +1 -0
- package/src/bin/playwright/pageCollector.ts +0 -2
- package/src/bin/playwright/templates.ts +2 -1
- package/src/bin/routes/Parser.ts +12 -5
- package/src/front/server-state/DataProxy.ts +136 -61
- package/src/front/server-state/SSR.ts +18 -2
- package/src/front/server-state/real.ts +16 -1
- package/src/front/server-state/serverStates.ts +26 -17
- package/src/front/server-state/useServerState.ts +10 -10
- package/src/front/url/search/useSearch.ts +1 -1
- package/src/front/url/search/useSearchValue.ts +25 -13
- package/src/front/wrapper/Custom.tsx +20 -4
- package/tests/data-proxy/create-dataproxy.test.ts +116 -0
- package/tests/{custom.test.ts → parse/custom.test.ts} +2 -2
- package/tests/{parse.test.ts → parse/parse.test.ts} +7 -7
- package/vite/plugin.ts +21 -15
- /package/tests/{content → parse/content}/1.html +0 -0
- /package/tests/{content → parse/content}/1_result.json +0 -0
- /package/tests/{content → parse/content}/2.html +0 -0
- /package/tests/{content → parse/content}/2_result.json +0 -0
- /package/tests/{content → parse/content}/3.html +0 -0
- /package/tests/{content → parse/content}/3_result.json +0 -0
- /package/tests/{content → parse/content}/4.html +0 -0
- /package/tests/{content → parse/content}/4_result.json +0 -0
- /package/tests/{content → parse/content}/custom.html +0 -0
- /package/tests/{content → parse/content}/custom.json +0 -0
- /package/tests/{content → parse/content}/index.html +0 -0
- /package/tests/{content → parse/content}/index.json +0 -0
- /package/tests/{content → parse/content}/index_with_templates.json +0 -0
- /package/tests/{content → parse/content}/templates.json +0 -0
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
|
+
import { ssr } from '../server-state/SSR.js';
|
|
4
|
+
import { SPLIT } from '../../bin/routes/Parser.js';
|
|
5
|
+
|
|
1
6
|
const Custom = ({ name, props, children }) => {
|
|
2
|
-
|
|
7
|
+
if (!ssr.current)
|
|
8
|
+
return jsx(Fragment, { children: children });
|
|
9
|
+
const exampleProps = JSON.stringify({ name, props: props() });
|
|
10
|
+
ssr.exportToJV = true;
|
|
11
|
+
const customProps = JSON.stringify({ name, props: props() });
|
|
12
|
+
ssr.exportToJV = false;
|
|
13
|
+
return (
|
|
14
|
+
//@ts-ignore
|
|
15
|
+
jsxs("custom", { children: [customProps, SPLIT, exampleProps, SPLIT, children] }));
|
|
3
16
|
};
|
|
4
17
|
|
|
5
18
|
export { Custom };
|
package/lib/vite/plugin.js
CHANGED
|
@@ -1,153 +1,16 @@
|
|
|
1
1
|
import { createServer } from 'vite';
|
|
2
2
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
3
3
|
import { chromium } from 'playwright';
|
|
4
|
-
import { createHash } from 'node:crypto';
|
|
5
|
-
import { writeFile } from 'fs/promises';
|
|
6
4
|
|
|
7
5
|
const pageCollector = async (page) => {
|
|
8
6
|
const state = await page.evaluate(() => {
|
|
9
7
|
const state = Object.fromEntries(window.$exportServerStates);
|
|
10
|
-
console.log("BROWSER", state);
|
|
11
8
|
return state;
|
|
12
9
|
});
|
|
13
|
-
console.log("CLIENT", state);
|
|
14
10
|
const root = await page.locator("#root").innerHTML();
|
|
15
11
|
return { root, state };
|
|
16
12
|
};
|
|
17
13
|
|
|
18
|
-
const normalizeHtmlWhitespace = (html) => {
|
|
19
|
-
return html
|
|
20
|
-
.replace(/\r?\n|\r/g, " ")
|
|
21
|
-
.replace(/\s+/g, " ")
|
|
22
|
-
.replace(/>\s+</g, "><")
|
|
23
|
-
.trim();
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
class Parser {
|
|
27
|
-
options;
|
|
28
|
-
openVar = "{{";
|
|
29
|
-
createVar = "}}";
|
|
30
|
-
createArray = "</loopwrapper";
|
|
31
|
-
createCustom = "</custom";
|
|
32
|
-
deepUp = "<loopwrapper";
|
|
33
|
-
deepUp2 = "<custom";
|
|
34
|
-
templates = {};
|
|
35
|
-
constructor(options) {
|
|
36
|
-
this.options = options;
|
|
37
|
-
}
|
|
38
|
-
parse(content) {
|
|
39
|
-
const tree = [];
|
|
40
|
-
this.handle(this.options?.normalize ? normalizeHtmlWhitespace(content) : content, tree);
|
|
41
|
-
return tree;
|
|
42
|
-
}
|
|
43
|
-
handle(content, tree) {
|
|
44
|
-
let match;
|
|
45
|
-
let deep = 0;
|
|
46
|
-
let lastIndex = 0;
|
|
47
|
-
const tagPattern = new RegExp(`(<loopwrapper(\\s+[^>]*)?>|</loopwrapper>|\{\{|\}\}|<custom(\\s+[^>]*)?>|</custom>)`, "gi");
|
|
48
|
-
while ((match = tagPattern.exec(content)) !== null) {
|
|
49
|
-
const currentTag = match[0];
|
|
50
|
-
const value = content.substring(lastIndex, match.index);
|
|
51
|
-
if (currentTag.startsWith(this.createArray)) {
|
|
52
|
-
deep--;
|
|
53
|
-
if (deep > 0)
|
|
54
|
-
continue;
|
|
55
|
-
this.createElement(tree, value);
|
|
56
|
-
}
|
|
57
|
-
else if (currentTag.startsWith(this.deepUp)) {
|
|
58
|
-
deep++;
|
|
59
|
-
if (deep > 1)
|
|
60
|
-
continue;
|
|
61
|
-
this.createElement(tree, value);
|
|
62
|
-
}
|
|
63
|
-
else if (currentTag.startsWith(this.createCustom)) {
|
|
64
|
-
deep--;
|
|
65
|
-
if (deep != 0)
|
|
66
|
-
continue;
|
|
67
|
-
this.createCustomElement(tree, value);
|
|
68
|
-
}
|
|
69
|
-
else if (currentTag.startsWith(this.deepUp2)) {
|
|
70
|
-
deep++;
|
|
71
|
-
if (deep > 1)
|
|
72
|
-
continue;
|
|
73
|
-
this.createElement(tree, value);
|
|
74
|
-
}
|
|
75
|
-
else if (currentTag == this.createVar) {
|
|
76
|
-
if (deep != 0)
|
|
77
|
-
continue;
|
|
78
|
-
this.createElement(tree, value, true);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
if (deep != 0)
|
|
82
|
-
continue;
|
|
83
|
-
this.createElement(tree, value);
|
|
84
|
-
}
|
|
85
|
-
lastIndex = match.index + currentTag.length;
|
|
86
|
-
}
|
|
87
|
-
if (lastIndex < content.length) {
|
|
88
|
-
const value = content.substring(lastIndex);
|
|
89
|
-
this.createElement(tree, value);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
createCustomElement(parent, value) {
|
|
93
|
-
const [name, ...props] = value.trimStart().split("|");
|
|
94
|
-
value = props.join("|");
|
|
95
|
-
parent.push({
|
|
96
|
-
type: "custom",
|
|
97
|
-
name,
|
|
98
|
-
props: value,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
createElement(parent, value, isVarible) {
|
|
102
|
-
if (isVarible)
|
|
103
|
-
return parent.push({
|
|
104
|
-
type: "value",
|
|
105
|
-
key: value,
|
|
106
|
-
});
|
|
107
|
-
if (value.trimStart().startsWith("ArrayDataKey=")) {
|
|
108
|
-
const [key, ...val] = value.trimStart().substring(13).split("|");
|
|
109
|
-
value = val.join("|");
|
|
110
|
-
const children = [];
|
|
111
|
-
this.handle(value, children);
|
|
112
|
-
return parent.push({
|
|
113
|
-
type: "array",
|
|
114
|
-
data: children,
|
|
115
|
-
key,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
if (value)
|
|
119
|
-
parent.push({
|
|
120
|
-
type: "html",
|
|
121
|
-
content: this.options?.templates ? this.createTemplate(value) : value,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
createTemplate(html) {
|
|
125
|
-
if (!(html in this.templates)) {
|
|
126
|
-
this.templates[html] = createHash("md5").update(Object.keys(this.templates).length.toString()).digest("hex");
|
|
127
|
-
}
|
|
128
|
-
return this.templates[html];
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const getRoutesAndTemplates = (pages, normalize = true, templates = true) => {
|
|
133
|
-
const routes = [];
|
|
134
|
-
const parser = new Parser({ normalize, templates });
|
|
135
|
-
for (const [id, template] of pages.entries()) {
|
|
136
|
-
const content = parser.parse(template.root);
|
|
137
|
-
const mask = template.mask.replaceAll("/", "\\/").replace(/{(.*?)}/, ".+?");
|
|
138
|
-
routes.push({
|
|
139
|
-
id,
|
|
140
|
-
content,
|
|
141
|
-
mask,
|
|
142
|
-
state: template.state,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
routes,
|
|
147
|
-
templates: parser.templates,
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
|
|
151
14
|
const urlStorage = new AsyncLocalStorage();
|
|
152
15
|
function hydration() {
|
|
153
16
|
if (process.env.CHILD_JINRAI_DEV_SERVER) {
|
|
@@ -157,6 +20,7 @@ function hydration() {
|
|
|
157
20
|
console.log("create mirror");
|
|
158
21
|
let mirrorServer = undefined;
|
|
159
22
|
let context = undefined;
|
|
23
|
+
let page = undefined;
|
|
160
24
|
let debugUrl = undefined;
|
|
161
25
|
createServer({
|
|
162
26
|
server: {
|
|
@@ -166,12 +30,13 @@ function hydration() {
|
|
|
166
30
|
mirrorServer = server;
|
|
167
31
|
await mirrorServer.listen();
|
|
168
32
|
debugUrl = mirrorServer.resolvedUrls?.local[0].slice(0, -1);
|
|
169
|
-
chromium.launch({ headless:
|
|
33
|
+
chromium.launch({ headless: false, devtools: false, channel: "chrome" }).then(async (browser) => {
|
|
170
34
|
console.log("create context");
|
|
171
35
|
context = await browser.newContext({
|
|
172
|
-
userAgent:
|
|
36
|
+
// userAgent: JinraiAgent,
|
|
173
37
|
locale: "ru-RU",
|
|
174
38
|
});
|
|
39
|
+
page = await context.newPage();
|
|
175
40
|
});
|
|
176
41
|
});
|
|
177
42
|
return {
|
|
@@ -188,23 +53,24 @@ function hydration() {
|
|
|
188
53
|
},
|
|
189
54
|
async transformIndexHtml(html) {
|
|
190
55
|
const currentUrl = urlStorage.getStore();
|
|
191
|
-
if (currentUrl &&
|
|
192
|
-
const page = await context.newPage();
|
|
56
|
+
if (currentUrl && page) {
|
|
193
57
|
await page.goto(debugUrl + currentUrl);
|
|
194
58
|
await page.waitForLoadState("networkidle");
|
|
195
|
-
const {
|
|
196
|
-
const { routes } = getRoutesAndTemplates([{ id: 1, state: {}, mask: currentUrl, root }], true, false)
|
|
197
|
-
console.log({ routes })
|
|
198
|
-
writeFile("./routs.json", JSON.stringify(routes, null, 2))
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return
|
|
59
|
+
const { state } = await pageCollector(page);
|
|
60
|
+
// const { routes } = getRoutesAndTemplates([{ id: 1, state: {}, mask: currentUrl, root }], true, false)
|
|
61
|
+
// console.log({ routes })
|
|
62
|
+
// writeFile("./routs.json", JSON.stringify(routes, null, 2))
|
|
63
|
+
// html = html.replace("<!--app-html-->", root)
|
|
64
|
+
html = html.replace("<!--app-head-->", JSON.stringify(state, null, 2));
|
|
65
|
+
return html;
|
|
202
66
|
}
|
|
203
67
|
return html;
|
|
204
68
|
},
|
|
205
69
|
closeWatcher() {
|
|
206
70
|
console.log("Stop server");
|
|
207
|
-
|
|
71
|
+
page?.close();
|
|
72
|
+
mirrorServer?.close();
|
|
73
|
+
context?.close();
|
|
208
74
|
},
|
|
209
75
|
};
|
|
210
76
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jinrai",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "A powerful library that analyzes your modern web application and automatically generates a perfectly rendered, static snapshot of its pages. Experience unparalleled loading speed and SEO clarity without the complexity of traditional SSR setups. Simply point Jinrai at your SPA and witness divine speed.",
|
|
5
5
|
"main": "lib/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -66,6 +66,10 @@
|
|
|
66
66
|
"./config": {
|
|
67
67
|
"types": "./lib/config/config.d.ts",
|
|
68
68
|
"import": "./lib/config/config.js"
|
|
69
|
+
},
|
|
70
|
+
"./vite": {
|
|
71
|
+
"types": "./lib/vite/plugin.d.ts",
|
|
72
|
+
"import": "./lib/vite/plugin.js"
|
|
69
73
|
}
|
|
70
74
|
}
|
|
71
75
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const JinraiAgent = "____JINRAI_AGENT____"
|
|
@@ -4,12 +4,10 @@ import { ServerStateMap } from "../../front/server-state/useServerState"
|
|
|
4
4
|
export const pageCollector = async (page: Page): Promise<{ state: ServerStateMap; root: string }> => {
|
|
5
5
|
const state = await page.evaluate(() => {
|
|
6
6
|
const state = Object.fromEntries((window as any).$exportServerStates)
|
|
7
|
-
console.log("BROWSER", state)
|
|
8
7
|
|
|
9
8
|
return state
|
|
10
9
|
})
|
|
11
10
|
|
|
12
|
-
console.log("CLIENT", state)
|
|
13
11
|
const root = await page.locator("#root").innerHTML()
|
|
14
12
|
|
|
15
13
|
return { root, state }
|
|
@@ -3,6 +3,7 @@ import Task from "../ui/task"
|
|
|
3
3
|
import { spinners } from "ora"
|
|
4
4
|
import { pageCollector } from "./pageCollector"
|
|
5
5
|
import { ServerValue } from "../../front/server-state/serverStates"
|
|
6
|
+
import { JinraiAgent } from "../agent/agent"
|
|
6
7
|
|
|
7
8
|
export interface PageData {
|
|
8
9
|
id: number
|
|
@@ -27,7 +28,7 @@ export const getRawPageData = async (
|
|
|
27
28
|
// const test_browser = await chromium.launch({ headless: true, channel: "chrome" })
|
|
28
29
|
|
|
29
30
|
const context = await browser.newContext({
|
|
30
|
-
userAgent:
|
|
31
|
+
userAgent: JinraiAgent,
|
|
31
32
|
locale: "ru-RU",
|
|
32
33
|
})
|
|
33
34
|
|
package/src/bin/routes/Parser.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { normalizeHtmlWhitespace } from "../content/normalizeContent"
|
|
2
2
|
import { createHash } from "node:crypto"
|
|
3
3
|
|
|
4
|
+
export const SPLIT = "@#UNIQ_SPLITTER#@"
|
|
5
|
+
|
|
6
|
+
interface CustomElement {
|
|
7
|
+
name: string
|
|
8
|
+
props: object
|
|
9
|
+
}
|
|
10
|
+
|
|
4
11
|
interface ParserOptions {
|
|
5
12
|
templates?: boolean
|
|
6
13
|
normalize?: boolean
|
|
@@ -27,7 +34,7 @@ interface ValueElement {
|
|
|
27
34
|
interface CustomElement {
|
|
28
35
|
type: "custom"
|
|
29
36
|
name: string
|
|
30
|
-
props:
|
|
37
|
+
props: object
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
export class Parser {
|
|
@@ -100,13 +107,13 @@ export class Parser {
|
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
createCustomElement(parent: Element[], value: string) {
|
|
103
|
-
const [
|
|
104
|
-
|
|
110
|
+
const [customProps, exampleProps, children] = value.split(SPLIT)
|
|
111
|
+
const custom = JSON.parse(customProps) as CustomElement
|
|
105
112
|
|
|
106
113
|
parent.push({
|
|
107
114
|
type: "custom",
|
|
108
|
-
name,
|
|
109
|
-
props:
|
|
115
|
+
name: custom.name,
|
|
116
|
+
props: custom.props,
|
|
110
117
|
})
|
|
111
118
|
}
|
|
112
119
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import { ssr } from "./SSR"
|
|
3
|
+
import { JinraiValue } from "../url/search/useSearchValue"
|
|
3
4
|
|
|
4
5
|
// IMPORT REACT
|
|
5
6
|
|
|
@@ -22,99 +23,173 @@ const getTarget = (data: any, path: string) => {
|
|
|
22
23
|
case "undefined":
|
|
23
24
|
case "symbol":
|
|
24
25
|
// эти типы можно просто завернуть
|
|
25
|
-
return {
|
|
26
|
+
return { $__ROOT__: data }
|
|
26
27
|
default:
|
|
27
28
|
return () => `{{${path}}}`
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
type WithDataProxy<T> = T & DataProxy
|
|
33
|
+
function createDataProxy<T>(data: T, path: string = ""): WithDataProxy<T> {
|
|
32
34
|
if (path.endsWith("@")) sources.set(path.slice(0, -1), data)
|
|
33
35
|
|
|
34
36
|
return new Proxy(getTarget(data, path), {
|
|
35
|
-
get: (
|
|
36
|
-
|
|
37
|
+
get: (_target: any, prop: PropertyKey) => {
|
|
38
|
+
if (ssr.exportToJV) {
|
|
39
|
+
return {
|
|
40
|
+
$JV: {
|
|
41
|
+
key: path + "/" + String(prop),
|
|
42
|
+
type: "proxy",
|
|
43
|
+
def: data,
|
|
44
|
+
},
|
|
45
|
+
} as { $JV?: JinraiValue }
|
|
46
|
+
}
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
// ---------------------------
|
|
49
|
+
// 1. Обработка символов
|
|
50
|
+
// ---------------------------
|
|
51
|
+
if (typeof prop === "symbol") {
|
|
40
52
|
switch (prop) {
|
|
41
|
-
// @ts-ignore
|
|
42
53
|
case Symbol.toPrimitive:
|
|
43
54
|
return (hint: string) => {
|
|
44
55
|
console.log("PROXYDATA", hint)
|
|
45
56
|
return `{{${path}}}`
|
|
46
57
|
}
|
|
47
|
-
|
|
58
|
+
|
|
48
59
|
case Symbol.toStringTag:
|
|
49
60
|
return "Object"
|
|
50
|
-
|
|
61
|
+
|
|
51
62
|
case Symbol.iterator:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
if (typeof data === "object" && data !== null && Symbol.iterator in (data as any)) {
|
|
64
|
+
return (data as any)[Symbol.iterator]
|
|
65
|
+
}
|
|
55
66
|
return undefined
|
|
67
|
+
}
|
|
68
|
+
}
|
|
56
69
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
// ---------------------------
|
|
71
|
+
// 2. DEV tools
|
|
72
|
+
// ---------------------------
|
|
73
|
+
if (!(typeof data === "object" && data !== null && prop in (data as any))) {
|
|
74
|
+
if (prop === "$$typeof" || prop === "type") {
|
|
75
|
+
return undefined
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (prop === "_debugInfo") {
|
|
79
|
+
return {
|
|
80
|
+
note: `State From Request (${path})`,
|
|
81
|
+
kind: typeof data,
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
preview: data,
|
|
84
|
+
}
|
|
64
85
|
}
|
|
86
|
+
}
|
|
65
87
|
|
|
66
|
-
//
|
|
67
|
-
|
|
88
|
+
// ---------------------------
|
|
89
|
+
// 3. SELF: $key → returns function
|
|
90
|
+
// ---------------------------
|
|
91
|
+
if (typeof prop === "string" && prop.startsWith("$")) {
|
|
92
|
+
return (key: string) => `{{${path + "/" + key}${"\\" + prop}}}`
|
|
93
|
+
}
|
|
68
94
|
|
|
69
|
-
//
|
|
95
|
+
// ---------------------------
|
|
96
|
+
// 4. Types special cases
|
|
97
|
+
// ---------------------------
|
|
70
98
|
switch (typeof data) {
|
|
71
99
|
case "string":
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return undefined
|
|
76
|
-
}
|
|
100
|
+
if (prop === "length" || prop === "entries") return undefined
|
|
101
|
+
break
|
|
102
|
+
|
|
77
103
|
case "number":
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return undefined
|
|
81
|
-
}
|
|
104
|
+
if (prop === "@@iterator") return undefined
|
|
105
|
+
break
|
|
82
106
|
|
|
83
107
|
default:
|
|
84
|
-
|
|
85
|
-
case "then":
|
|
86
|
-
return undefined
|
|
87
|
-
}
|
|
108
|
+
if (prop === "then") return undefined
|
|
88
109
|
}
|
|
89
110
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
case "forEach":
|
|
96
|
-
return (callback: (arg0: DataProxy) => any) =>
|
|
97
|
-
React.createElement("loopwrapper", null, [
|
|
98
|
-
`ArrayDataKey=${path}|`,
|
|
99
|
-
Object.entries(data)
|
|
100
|
-
.slice(0, 1)
|
|
101
|
-
.map(([key, itm]) => callback(createDataProxy(itm, `${path}/[ITEM=${key}]`))),
|
|
102
|
-
])
|
|
103
|
-
case "getValue":
|
|
104
|
-
return () => data
|
|
105
|
-
case "toJSON":
|
|
106
|
-
return () => {
|
|
107
|
-
console.log("dataproxy toJSON", path, data)
|
|
108
|
-
return ssr.exportParams ? `{{${path}}}` : data
|
|
109
|
-
}
|
|
110
|
-
default:
|
|
111
|
-
if (data && (typeof data[prop] == "object" || Array.isArray(data[prop]))) {
|
|
112
|
-
return createDataProxy(data[prop], path + "/" + prop)
|
|
113
|
-
}
|
|
114
|
-
return `{{${path + "/" + prop}}}`
|
|
111
|
+
// ---------------------------
|
|
112
|
+
// 5. Array-like handlers
|
|
113
|
+
// ---------------------------
|
|
114
|
+
if (prop === "find") {
|
|
115
|
+
return (data as any)[prop]
|
|
115
116
|
}
|
|
117
|
+
|
|
118
|
+
if (prop === "length") {
|
|
119
|
+
if (Array.isArray(data)) {
|
|
120
|
+
return data.length
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (prop === "map" || prop === "forEach") {
|
|
125
|
+
return (callback: (arg: DataProxy) => any) =>
|
|
126
|
+
React.createElement("loopwrapper", null, [
|
|
127
|
+
`ArrayDataKey=${path}|`,
|
|
128
|
+
Object.entries(data as any)
|
|
129
|
+
.slice(0, 1)
|
|
130
|
+
.map(([key, itm]) => callback(createDataProxy(itm, `${path}/[ITEM=${key}]`))),
|
|
131
|
+
])
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---------------------------
|
|
135
|
+
// 6. getValue
|
|
136
|
+
// ---------------------------
|
|
137
|
+
if (prop === "getValue") {
|
|
138
|
+
return () => data
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ---------------------------
|
|
142
|
+
// 7. toJSON
|
|
143
|
+
// ---------------------------
|
|
144
|
+
if (prop === "toJSON") {
|
|
145
|
+
return () => {
|
|
146
|
+
console.log("dataproxy toJSON", path, data)
|
|
147
|
+
|
|
148
|
+
return ssr.exportParams
|
|
149
|
+
? `{{${path}}}`
|
|
150
|
+
: ({
|
|
151
|
+
$JV: {
|
|
152
|
+
key: path,
|
|
153
|
+
type: "proxy",
|
|
154
|
+
def: data,
|
|
155
|
+
separator: "",
|
|
156
|
+
},
|
|
157
|
+
} as { $JV?: JinraiValue })
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ---------------------------
|
|
162
|
+
// 8. Nested object
|
|
163
|
+
// ---------------------------
|
|
164
|
+
const value = (data as any)[prop]
|
|
165
|
+
if (!ssr.exportParams) {
|
|
166
|
+
return value
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (value && (typeof value === "object" || Array.isArray(value))) {
|
|
170
|
+
return createDataProxy(value, path + "/" + String(prop))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// if (ssr.exportParams) {
|
|
174
|
+
|
|
175
|
+
// if (typeof value == "string") {
|
|
176
|
+
// const key = `{{${path + "/" + String(prop)}}}`
|
|
177
|
+
// const jv = getJinraiValue(key, "proxyValue", "", value)
|
|
178
|
+
|
|
179
|
+
// return value.bindSource(jv)
|
|
180
|
+
// }
|
|
181
|
+
|
|
182
|
+
// return key
|
|
183
|
+
// } else {
|
|
184
|
+
// return value
|
|
185
|
+
// }
|
|
186
|
+
|
|
187
|
+
// ---------------------------
|
|
188
|
+
// 9. Final primitive fallback
|
|
189
|
+
// ---------------------------
|
|
190
|
+
return `{{${path + "/" + String(prop)}}}`
|
|
116
191
|
},
|
|
117
|
-
})
|
|
192
|
+
}) as any
|
|
118
193
|
}
|
|
119
194
|
|
|
120
195
|
export default createDataProxy
|
|
@@ -1,4 +1,20 @@
|
|
|
1
|
+
import { JinraiAgent } from "../../bin/agent/agent"
|
|
2
|
+
|
|
1
3
|
export const ssr = {
|
|
2
|
-
current:
|
|
3
|
-
exportParams:
|
|
4
|
+
current: navigator.userAgent == JinraiAgent,
|
|
5
|
+
exportParams: true,
|
|
6
|
+
exportToJV: false,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (window != undefined) {
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
window.__ssr = ssr
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const stringifyInput = (input: any) => {
|
|
15
|
+
ssr.exportParams = false
|
|
16
|
+
const result = JSON.stringify(input)
|
|
17
|
+
ssr.exportParams = true
|
|
18
|
+
|
|
19
|
+
return result
|
|
4
20
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ssr } from "./SSR"
|
|
2
2
|
import { sources } from "./DataProxy"
|
|
3
|
+
import { getJinraiValue, JinraiValue } from "../url/search/useSearchValue"
|
|
3
4
|
|
|
4
5
|
export function real<T>(value: T): T {
|
|
5
6
|
if (!ssr.current) return value
|
|
@@ -8,7 +9,13 @@ export function real<T>(value: T): T {
|
|
|
8
9
|
case "number":
|
|
9
10
|
return value
|
|
10
11
|
case "string":
|
|
11
|
-
|
|
12
|
+
if (value.startsWith("{{") && value.endsWith("}}")) {
|
|
13
|
+
const result = getArrayByPath(value.slice(2, -2))
|
|
14
|
+
|
|
15
|
+
return wrapSource<T>(result, getJinraiValue(value, "proxy", "", result))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return value
|
|
12
19
|
|
|
13
20
|
case "object":
|
|
14
21
|
// @ts-ignore
|
|
@@ -24,6 +31,14 @@ export function real<T>(value: T): T {
|
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
|
|
34
|
+
const wrapSource = <T>(value: T, source: JinraiValue): T => {
|
|
35
|
+
if (typeof value == "string") {
|
|
36
|
+
return value.bindSource(source) as T
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return value
|
|
40
|
+
}
|
|
41
|
+
|
|
27
42
|
const getArrayByPath = (path: string) => {
|
|
28
43
|
const [sourceIndex, requestPath] = path.split("@", 2)
|
|
29
44
|
const keys = requestPath.split("/")
|