jinrai 1.1.1 → 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.
Files changed (58) hide show
  1. package/index.ts +4 -0
  2. package/lib/bin/bin.js +13 -9
  3. package/lib/index.d.ts +2 -0
  4. package/lib/index.js +1 -0
  5. package/lib/src/bin/agent/agent.d.ts +1 -0
  6. package/lib/src/bin/agent/agent.js +3 -0
  7. package/lib/src/bin/playwright/pageCollector.d.ts +2 -1
  8. package/lib/src/bin/playwright/templates.d.ts +2 -6
  9. package/lib/src/bin/routes/Parser.d.ts +6 -1
  10. package/lib/src/bin/routes/Parser.js +5 -0
  11. package/lib/src/bin/routes/getRoutes.d.ts +3 -2
  12. package/lib/src/front/server-state/DataProxy.d.ts +2 -1
  13. package/lib/src/front/server-state/DataProxy.js +119 -60
  14. package/lib/src/front/server-state/SSR.d.ts +2 -0
  15. package/lib/src/front/server-state/SSR.js +16 -3
  16. package/lib/src/front/server-state/real.js +12 -1
  17. package/lib/src/front/server-state/serverStates.d.ts +19 -5
  18. package/lib/src/front/server-state/serverStates.js +29 -15
  19. package/lib/src/front/server-state/useServerState.d.ts +3 -12
  20. package/lib/src/front/server-state/useServerState.js +12 -12
  21. package/lib/src/front/url/search/useSearch.js +1 -1
  22. package/lib/src/front/url/search/useSearchValue.d.ts +11 -5
  23. package/lib/src/front/url/search/useSearchValue.js +15 -7
  24. package/lib/src/front/wrapper/Custom.d.ts +3 -3
  25. package/lib/src/front/wrapper/Custom.js +11 -2
  26. package/lib/vite/plugin.js +18 -149
  27. package/package.json +7 -1
  28. package/src/bin/agent/agent.ts +1 -0
  29. package/src/bin/playwright/pageCollector.ts +6 -3
  30. package/src/bin/playwright/templates.ts +5 -9
  31. package/src/bin/routes/Parser.ts +12 -5
  32. package/src/bin/routes/getRoutes.ts +4 -3
  33. package/src/front/server-state/DataProxy.ts +136 -61
  34. package/src/front/server-state/SSR.ts +18 -2
  35. package/src/front/server-state/real.ts +16 -1
  36. package/src/front/server-state/serverStates.ts +54 -20
  37. package/src/front/server-state/useServerState.ts +17 -26
  38. package/src/front/url/search/useSearch.ts +1 -1
  39. package/src/front/url/search/useSearchValue.ts +29 -13
  40. package/src/front/wrapper/Custom.tsx +20 -4
  41. package/tests/data-proxy/create-dataproxy.test.ts +116 -0
  42. package/tests/{custom.test.ts → parse/custom.test.ts} +2 -2
  43. package/tests/{parse.test.ts → parse/parse.test.ts} +7 -7
  44. package/vite/plugin.ts +21 -15
  45. /package/tests/{content → parse/content}/1.html +0 -0
  46. /package/tests/{content → parse/content}/1_result.json +0 -0
  47. /package/tests/{content → parse/content}/2.html +0 -0
  48. /package/tests/{content → parse/content}/2_result.json +0 -0
  49. /package/tests/{content → parse/content}/3.html +0 -0
  50. /package/tests/{content → parse/content}/3_result.json +0 -0
  51. /package/tests/{content → parse/content}/4.html +0 -0
  52. /package/tests/{content → parse/content}/4_result.json +0 -0
  53. /package/tests/{content → parse/content}/custom.html +0 -0
  54. /package/tests/{content → parse/content}/custom.json +0 -0
  55. /package/tests/{content → parse/content}/index.html +0 -0
  56. /package/tests/{content → parse/content}/index.json +0 -0
  57. /package/tests/{content → parse/content}/index_with_templates.json +0 -0
  58. /package/tests/{content → parse/content}/templates.json +0 -0
@@ -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 { value: data }
26
+ return { $__ROOT__: data }
26
27
  default:
27
28
  return () => `{{${path}}}`
28
29
  }
29
30
  }
30
31
 
31
- const createDataProxy = (data: any, path: string = ""): DataProxy => {
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: (_: any, prop: string) => {
36
- // if (typeof prop == "symbol") return data[prop]
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
- if (!(typeof data == "object" && data !== null && prop in data))
39
- // DEV TOOLS
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
- // @ts-ignore
58
+
48
59
  case Symbol.toStringTag:
49
60
  return "Object"
50
- // @ts-ignore
61
+
51
62
  case Symbol.iterator:
52
- return data[Symbol.iterator]
53
- case "$$typeof":
54
- case "type":
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
- case "_debugInfo":
58
- return {
59
- note: `State From Request (${path})`,
60
- kind: typeof data,
61
- timestamp: Date.now(),
62
- preview: data,
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
- // SELF
67
- if (prop.startsWith("$")) return (key: string) => `{{${path + "/" + key}${"\\" + prop}}}`
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
- // TYPES
95
+ // ---------------------------
96
+ // 4. Types special cases
97
+ // ---------------------------
70
98
  switch (typeof data) {
71
99
  case "string":
72
- switch (prop) {
73
- case "length":
74
- case "entries":
75
- return undefined
76
- }
100
+ if (prop === "length" || prop === "entries") return undefined
101
+ break
102
+
77
103
  case "number":
78
- switch (prop) {
79
- case "@@iterator":
80
- return undefined
81
- }
104
+ if (prop === "@@iterator") return undefined
105
+ break
82
106
 
83
107
  default:
84
- switch (prop) {
85
- case "then":
86
- return undefined
87
- }
108
+ if (prop === "then") return undefined
88
109
  }
89
110
 
90
- // OTHER
91
- switch (prop) {
92
- case "find":
93
- return data[prop]
94
- case "map":
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: navigator.userAgent == "____JINRAI_CLIENT____",
3
- exportParams: false,
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
- return value.startsWith("{{") && value.endsWith("}}") ? getArrayByPath(value.slice(2, -2)) : value
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("/")
@@ -1,36 +1,70 @@
1
1
  import createDataProxy from "./DataProxy"
2
- import { ssr } from "./SSR"
3
- import { ServerStateOptions } from "./useServerState"
2
+ import { ServerKey } from "./useServerState"
4
3
 
5
- export type ServerValue = any
4
+ // @ts-ignore
5
+ const initialState = { ...(window?.__appc__?.state ?? {}) }
6
+ // @ts-ignore
7
+ const serverErrors = [...(window?.__appc__?.errors ?? [])]
8
+
9
+ if (serverErrors.length) {
10
+ console.error("SERVER:", serverErrors)
11
+ }
6
12
 
7
- export const serverStates = new Map<string, string>()
8
13
  if (window != undefined) {
9
14
  // @ts-ignore
10
- window.__serverExportStates__ = serverStates
15
+ delete window.__appc__
11
16
  }
12
17
 
13
- export const getServerValue = (key: string, def?: ServerValue) => {
14
- if (key == "") {
15
- return [def, false]
18
+ interface Request {
19
+ method: string
20
+ url: string
21
+ input: any
22
+ }
23
+
24
+ export type ServerValue = {
25
+ value: any
26
+ options?: {
27
+ source: {
28
+ request?: Request
29
+ }
16
30
  }
31
+ key: ServerKey
32
+ }
33
+
34
+ export const serverStates = new Map<string, ServerValue>()
35
+ const idents: string[] = []
17
36
 
37
+ if (window != undefined) {
38
+ console.log("init $exportServerStates")
18
39
  // @ts-ignore
19
- if (window != undefined && window?.__serverInitialStates__ && key in window.__serverInitialStates__) {
20
- // @ts-ignore
21
- return [window.__serverInitialStates__[key], true]
22
- }
40
+ window.$exportServerStates = serverStates
41
+ }
23
42
 
24
- return [serverStates.get(key) ?? def, false]
43
+ const getIdent = (key: ServerKey): string => {
44
+ return Array.isArray(key) ? key.join("-") : key
25
45
  }
26
46
 
27
- export const setServerValue = (key: string, value: ServerValue, options?: ServerStateOptions) => {
28
- ssr.exportParams = true
29
- const json = JSON.stringify({ value, options })
30
- ssr.exportParams = false
47
+ export const getServerValue = (key?: ServerKey, def?: ServerValue["value"], options?: ServerValue["options"]) => {
48
+ if (key == undefined) {
49
+ return [def, false]
50
+ }
51
+ const ident = getIdent(key)
52
+ serverStates.set(ident, { options, value: !options?.source ? def : undefined, key })
53
+
54
+ if (ident in initialState) {
55
+ const result = initialState[ident]
56
+ // delete initialState[ident]
31
57
 
32
- console.log(key, json)
33
- serverStates.set(key, json)
58
+ console.log("HAS", ident, result)
59
+
60
+ return ["data" in result ? result.data : result, true]
61
+ }
62
+
63
+ return [def, false]
64
+ }
34
65
 
35
- return createDataProxy(value, `${key}@`)
66
+ export const setServerValue = (key: ServerKey, value: ServerValue["value"], options?: ServerValue["options"]) => {
67
+ const ident = getIdent(key)
68
+ serverStates.set(ident, { options, value: !options?.source ? value : undefined, key })
69
+ return createDataProxy(value, `${ident}@`)
36
70
  }
@@ -1,33 +1,24 @@
1
- import { Dispatch, SetStateAction, useState } from "react"
1
+ import { Dispatch, SetStateAction, useRef, useState } from "react"
2
2
  import { ssr } from "./SSR"
3
3
  import { getServerValue, ServerValue, setServerValue } from "./serverStates"
4
4
 
5
- interface Request {
6
- method: string
7
- url: string
8
- input: any
9
- }
5
+ export type ServerStateMap = Record<string, ServerValue>
6
+ export type ServerKey = string | string[]
10
7
 
11
- export interface ServerStateOptions {
12
- source: {
13
- request?: Request
14
- }
15
- }
16
-
17
- export const useServerState = <T extends ServerValue>(
18
- serverKey: string,
8
+ export const useServerState = <T extends ServerValue["value"]>(
9
+ serverKey: ServerKey | undefined,
19
10
  initialValue: T,
20
- options?: ServerStateOptions,
11
+ options?: ServerValue["options"],
21
12
  ) => {
22
- const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue)
13
+ const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue, options)
23
14
  const [value, setStateValue] = useState(serverValue)
24
- const [isInit, setIsInit] = useState(isInitOnServer)
15
+ const isInit = useRef(isInitOnServer)
25
16
 
26
17
  const setValue: Dispatch<SetStateAction<T>> = (value: T | ((prevState: T) => T)) => {
27
18
  setStateValue((prev: T) => {
28
19
  const result = value instanceof Function ? (value as (prevState: T) => T)(prev) : value
29
20
 
30
- if (serverKey && ssr.current) {
21
+ if (serverKey != undefined && ssr.current) {
31
22
  return setServerValue(serverKey, result, options)
32
23
  }
33
24
 
@@ -35,14 +26,14 @@ export const useServerState = <T extends ServerValue>(
35
26
  })
36
27
  }
37
28
 
38
- const initOnServer = () => {
39
- if (isInit) {
40
- setIsInit(false)
41
- return true
42
- }
29
+ // const initOnServer = () => {
30
+ // if (isInit.current) {
31
+ // isInit.current = false
32
+ // return true
33
+ // }
43
34
 
44
- return false
45
- }
35
+ // return false
36
+ // }
46
37
 
47
- return [value, setValue, initOnServer] as [T, Dispatch<SetStateAction<T>>, () => boolean]
38
+ return [value, setValue, isInitOnServer] as [T, Dispatch<SetStateAction<T>>, boolean]
48
39
  }
@@ -8,7 +8,7 @@ export const useSearch = (): string => {
8
8
  const value = useMemo(() => location.search.substring(1), deps ? deps : [])
9
9
 
10
10
  const stableValue = useMemo(() => {
11
- return ssr.current ? value.bindSource(getJinraiValue("", "search", "", "")) : value
11
+ return ssr.current ? value.bindSource(getJinraiValue("", "searchFull", "", "")) : value
12
12
  }, [value])
13
13
 
14
14
  return stableValue
@@ -2,32 +2,43 @@ import { parseAsArrayOf, parseAsString, useQueryState, UseQueryStateReturn } fro
2
2
  import { useMemo } from "react"
3
3
  import { ssr } from "../../server-state/SSR"
4
4
 
5
+ export interface JinraiValue {
6
+ key: string
7
+ type: "searchArray" | "searchString" | "proxy" | "searchFull" | "paramsIndex"
8
+ separator: string
9
+ def: any
10
+ }
11
+
5
12
  declare global {
6
13
  interface String {
7
- source?: string
14
+ $JV?: JinraiValue
8
15
  toJSON: () => string
9
- bindSource: (source: string) => string
16
+ bindSource: (source: JinraiValue) => string
10
17
  }
11
18
  interface Array<T> {
12
- source?: string
19
+ $JV?: JinraiValue
13
20
  toJSON(): any
14
- bindSource(source: string): T[]
21
+ bindSource(source: JinraiValue): T[]
15
22
  }
16
23
  }
17
24
 
18
25
  function toJSON() {
19
- // @ts-ignore
20
- if (ssr.exportParams) return this.source
26
+ if (ssr.exportParams) {
27
+ // @ts-ignore
28
+ const $JV = this.$JV
29
+ // @ts-ignore
30
+ return $JV ? { $JV } : this
31
+ }
21
32
  // @ts-ignore
22
33
  return this
23
34
  }
24
35
 
25
36
  if (true) {
26
- String.prototype.source = undefined
37
+ String.prototype.$JV = undefined
27
38
  String.prototype.toJSON = toJSON
28
- String.prototype.bindSource = function (source: string): string {
39
+ String.prototype.bindSource = function (source: JinraiValue): string {
29
40
  const result = new String(this)
30
- result.source = source
41
+ result.$JV = source
31
42
  return result as string
32
43
  }
33
44
 
@@ -36,8 +47,8 @@ if (true) {
36
47
  }
37
48
 
38
49
  if (!Array.prototype.bindSource) {
39
- Array.prototype.bindSource = function (source: string) {
40
- this.source = source
50
+ Array.prototype.bindSource = function (source: JinraiValue) {
51
+ this.$JV = source
41
52
  return this
42
53
  }
43
54
  }
@@ -67,6 +78,11 @@ export const useSearchArray = (
67
78
  return [stableValue, setValue]
68
79
  }
69
80
 
70
- export const getJinraiValue = (key: string, type: string, separator: string, def: any) => {
71
- return `@JV[[${JSON.stringify({ key, type, separator, def })}]]`
81
+ export const getJinraiValue = (key: string, type: JinraiValue["type"], separator: string, def: any): JinraiValue => {
82
+ return {
83
+ key,
84
+ type,
85
+ separator,
86
+ def,
87
+ }
72
88
  }
@@ -1,14 +1,30 @@
1
- import type { FC, ReactElement, ReactNode } from "react"
1
+ import { Fragment, type ReactElement, type ReactNode } from "react"
2
2
  import { ssr } from "../server-state/SSR"
3
+ import { SPLIT } from "../../bin/routes/Parser"
3
4
 
4
5
  interface CustomProps {
5
6
  name: string
6
- props: object
7
+ props: () => object
7
8
  children: ReactNode
8
9
  }
9
10
 
10
11
  export const Custom = ({ name, props, children }: CustomProps) => {
11
- if (!ssr.current) return children as ReactElement
12
+ if (!ssr.current) return <Fragment>{children as ReactElement}</Fragment>
12
13
 
13
- return `<custom>${JSON.stringify({ name, props })}<custom>`
14
+ const exampleProps = JSON.stringify({ name, props: props() })
15
+ ssr.exportToJV = true
16
+ const customProps = JSON.stringify({ name, props: props() })
17
+ ssr.exportToJV = false
18
+
19
+ return (
20
+ //@ts-ignore
21
+ <custom>
22
+ {customProps}
23
+ {SPLIT}
24
+ {exampleProps}
25
+ {SPLIT}
26
+ {children}
27
+ {/* @ts-ignore */}
28
+ </custom>
29
+ )
14
30
  }