@alstar/studio 0.0.0-beta.2 → 0.0.0-beta.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/components/layout.ts +10 -1
- package/index.ts +2 -0
- package/package.json +3 -4
- package/public/main.css +2 -1
- package/public/main.js +15 -14
- package/utils/get-config.ts +1 -1
- package/utils/html.ts +247 -0
package/components/layout.ts
CHANGED
|
@@ -34,7 +34,16 @@ export default (props: {
|
|
|
34
34
|
type="module"
|
|
35
35
|
src="https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js"
|
|
36
36
|
></script>
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
<script type="importmap">
|
|
39
|
+
{
|
|
40
|
+
"imports": {
|
|
41
|
+
"@barba/core": "https://esm.sh/@barba/core@2.10.3/dist/barba.mjs",
|
|
42
|
+
"sortablejs": "https://esm.sh/sortablejs@1.15.6/modular/sortable.core.esm.js",
|
|
43
|
+
"ink-mde": "https://esm.sh/ink-mde@0.34.0"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
38
47
|
</head>
|
|
39
48
|
|
|
40
49
|
<body data-barba="wrapper">
|
package/index.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { serveStatic } from '@hono/node-server/serve-static'
|
|
|
14
14
|
import { createStudioTables } from './utils/create-studio-tables.ts'
|
|
15
15
|
import { fileBasedRouter } from './utils/file-based-router.ts'
|
|
16
16
|
|
|
17
|
+
export { html, type HtmlEscapedString } from './utils/html.ts'
|
|
18
|
+
|
|
17
19
|
export let structure: types.Structure
|
|
18
20
|
export let rootdir = '/node_modules/@alstar/studio'
|
|
19
21
|
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alstar/studio",
|
|
3
|
-
"version": "0.0.0-beta.
|
|
3
|
+
"version": "0.0.0-beta.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@hono/node-server": "^1.18.1",
|
|
8
8
|
"@starfederation/datastar-sdk": "1.0.0-RC.1",
|
|
9
9
|
"hono": "^4.8.12",
|
|
10
|
-
"
|
|
11
|
-
"@alstar/ui": "0.0.0-beta.1"
|
|
12
|
-
"@alstar/db": "0.0.0-beta.1"
|
|
10
|
+
"@alstar/db": "0.0.0-beta.1",
|
|
11
|
+
"@alstar/ui": "0.0.0-beta.1"
|
|
13
12
|
},
|
|
14
13
|
"devDependencies": {
|
|
15
14
|
"@types/node": "^24.1.0",
|
package/public/main.css
CHANGED
package/public/main.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import barba from '@barba/core'
|
|
2
|
+
import Sortable from 'sortablejs'
|
|
3
|
+
// import { wrap } from 'ink-mde'
|
|
3
4
|
|
|
4
5
|
barba.init({
|
|
5
6
|
views: [
|
|
@@ -27,17 +28,17 @@ function init() {
|
|
|
27
28
|
})
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
// ink-mde
|
|
31
|
-
{
|
|
32
|
-
|
|
31
|
+
// // ink-mde
|
|
32
|
+
// {
|
|
33
|
+
// const el = document.querySelector('textarea')
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
35
|
+
// if (el) {
|
|
36
|
+
// wrap(el, {
|
|
37
|
+
// interface: {
|
|
38
|
+
// // appearance: InkValues.Appearance.Auto,
|
|
39
|
+
// attribution: false,
|
|
40
|
+
// },
|
|
41
|
+
// })
|
|
42
|
+
// }
|
|
43
|
+
// }
|
|
43
44
|
}
|
package/utils/get-config.ts
CHANGED
package/utils/html.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
export const HtmlEscapedCallbackPhase = {
|
|
2
|
+
Stringify: 1,
|
|
3
|
+
BeforeStream: 2,
|
|
4
|
+
Stream: 3,
|
|
5
|
+
} as const
|
|
6
|
+
type HtmlEscapedCallbackOpts = {
|
|
7
|
+
buffer?: [string]
|
|
8
|
+
phase: (typeof HtmlEscapedCallbackPhase)[keyof typeof HtmlEscapedCallbackPhase]
|
|
9
|
+
context: Readonly<object> // An object unique to each JSX tree. This object is used as the WeakMap key.
|
|
10
|
+
}
|
|
11
|
+
export type HtmlEscapedCallback = (
|
|
12
|
+
opts: HtmlEscapedCallbackOpts,
|
|
13
|
+
) => Promise<string> | undefined
|
|
14
|
+
export type HtmlEscaped = {
|
|
15
|
+
isEscaped: true
|
|
16
|
+
callbacks?: HtmlEscapedCallback[]
|
|
17
|
+
}
|
|
18
|
+
export type HtmlEscapedString = string & HtmlEscaped
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* StringBuffer contains string and Promise<string> alternately
|
|
22
|
+
* The length of the array will be odd, the odd numbered element will be a string,
|
|
23
|
+
* and the even numbered element will be a Promise<string>.
|
|
24
|
+
* When concatenating into a single string, it must be processed from the tail.
|
|
25
|
+
* @example
|
|
26
|
+
* [
|
|
27
|
+
* 'framework.',
|
|
28
|
+
* Promise.resolve('ultra fast'),
|
|
29
|
+
* 'a ',
|
|
30
|
+
* Promise.resolve('is '),
|
|
31
|
+
* 'Hono',
|
|
32
|
+
* ]
|
|
33
|
+
*/
|
|
34
|
+
export type StringBuffer = (string | Promise<string>)[]
|
|
35
|
+
export type StringBufferWithCallbacks = StringBuffer & {
|
|
36
|
+
callbacks: HtmlEscapedCallback[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const raw = (
|
|
40
|
+
value: unknown,
|
|
41
|
+
callbacks?: HtmlEscapedCallback[],
|
|
42
|
+
): HtmlEscapedString => {
|
|
43
|
+
const escapedString = new String(value) as HtmlEscapedString
|
|
44
|
+
escapedString.isEscaped = true
|
|
45
|
+
escapedString.callbacks = callbacks
|
|
46
|
+
|
|
47
|
+
return escapedString
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The `escapeToBuffer` implementation is based on code from the MIT licensed `react-dom` package.
|
|
51
|
+
// https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/server/escapeTextForBrowser.js
|
|
52
|
+
|
|
53
|
+
const escapeRe = /[&<>'"]/
|
|
54
|
+
|
|
55
|
+
export const stringBufferToString = async (
|
|
56
|
+
buffer: StringBuffer,
|
|
57
|
+
callbacks: HtmlEscapedCallback[] | undefined,
|
|
58
|
+
): Promise<HtmlEscapedString> => {
|
|
59
|
+
let str = ''
|
|
60
|
+
callbacks ||= []
|
|
61
|
+
const resolvedBuffer = await Promise.all(buffer)
|
|
62
|
+
for (let i = resolvedBuffer.length - 1; ; i--) {
|
|
63
|
+
str += resolvedBuffer[i]
|
|
64
|
+
i--
|
|
65
|
+
if (i < 0) {
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let r = resolvedBuffer[i]
|
|
70
|
+
if (typeof r === 'object') {
|
|
71
|
+
callbacks.push(...((r as HtmlEscapedString).callbacks || []))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const isEscaped = (r as HtmlEscapedString).isEscaped
|
|
75
|
+
r = await (typeof r === 'object' ? (r as HtmlEscapedString).toString() : r)
|
|
76
|
+
if (typeof r === 'object') {
|
|
77
|
+
callbacks.push(...((r as HtmlEscapedString).callbacks || []))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if ((r as HtmlEscapedString).isEscaped ?? isEscaped) {
|
|
81
|
+
str += r
|
|
82
|
+
} else {
|
|
83
|
+
const buf = [str]
|
|
84
|
+
escapeToBuffer(r, buf)
|
|
85
|
+
str = buf[0]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return raw(str, callbacks)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const escapeToBuffer = (str: string, buffer: StringBuffer): void => {
|
|
93
|
+
const match = str.search(escapeRe)
|
|
94
|
+
if (match === -1) {
|
|
95
|
+
buffer[0] += str
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let escape
|
|
100
|
+
let index
|
|
101
|
+
let lastIndex = 0
|
|
102
|
+
|
|
103
|
+
for (index = match; index < str.length; index++) {
|
|
104
|
+
switch (str.charCodeAt(index)) {
|
|
105
|
+
case 34: // "
|
|
106
|
+
escape = '"'
|
|
107
|
+
break
|
|
108
|
+
case 39: // '
|
|
109
|
+
escape = '''
|
|
110
|
+
break
|
|
111
|
+
case 38: // &
|
|
112
|
+
escape = '&'
|
|
113
|
+
break
|
|
114
|
+
case 60: // <
|
|
115
|
+
escape = '<'
|
|
116
|
+
break
|
|
117
|
+
case 62: // >
|
|
118
|
+
escape = '>'
|
|
119
|
+
break
|
|
120
|
+
default:
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
buffer[0] += str.substring(lastIndex, index) + escape
|
|
125
|
+
lastIndex = index + 1
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
buffer[0] += str.substring(lastIndex, index)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const resolveCallbackSync = (
|
|
132
|
+
str: string | HtmlEscapedString,
|
|
133
|
+
): string => {
|
|
134
|
+
const callbacks = (str as HtmlEscapedString)
|
|
135
|
+
.callbacks as HtmlEscapedCallback[]
|
|
136
|
+
if (!callbacks?.length) {
|
|
137
|
+
return str
|
|
138
|
+
}
|
|
139
|
+
const buffer: [string] = [str]
|
|
140
|
+
const context = {}
|
|
141
|
+
|
|
142
|
+
callbacks.forEach((c) =>
|
|
143
|
+
c({ phase: HtmlEscapedCallbackPhase.Stringify, buffer, context }),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return buffer[0]
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const resolveCallback = async (
|
|
150
|
+
str: string | HtmlEscapedString | Promise<string>,
|
|
151
|
+
phase: (typeof HtmlEscapedCallbackPhase)[keyof typeof HtmlEscapedCallbackPhase],
|
|
152
|
+
preserveCallbacks: boolean,
|
|
153
|
+
context: object,
|
|
154
|
+
buffer?: [string],
|
|
155
|
+
): Promise<string> => {
|
|
156
|
+
if (typeof str === 'object' && !(str instanceof String)) {
|
|
157
|
+
if (!((str as unknown) instanceof Promise)) {
|
|
158
|
+
str = (str as unknown as string).toString() // HtmlEscapedString object to string
|
|
159
|
+
}
|
|
160
|
+
if ((str as string | Promise<string>) instanceof Promise) {
|
|
161
|
+
str = await (str as unknown as Promise<string>)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const callbacks = (str as HtmlEscapedString)
|
|
166
|
+
.callbacks as HtmlEscapedCallback[]
|
|
167
|
+
if (!callbacks?.length) {
|
|
168
|
+
return Promise.resolve(str)
|
|
169
|
+
}
|
|
170
|
+
if (buffer) {
|
|
171
|
+
buffer[0] += str
|
|
172
|
+
} else {
|
|
173
|
+
buffer = [str as string]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const resStr = Promise.all(
|
|
177
|
+
callbacks.map((c) => c({ phase, buffer, context })),
|
|
178
|
+
).then((res) =>
|
|
179
|
+
Promise.all(
|
|
180
|
+
res
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
.filter<string>(Boolean as any)
|
|
183
|
+
.map((str) => resolveCallback(str, phase, false, context, buffer)),
|
|
184
|
+
).then(() => (buffer as [string])[0]),
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if (preserveCallbacks) {
|
|
188
|
+
return raw(await resStr, callbacks)
|
|
189
|
+
} else {
|
|
190
|
+
return resStr
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const html = (
|
|
195
|
+
strings: TemplateStringsArray,
|
|
196
|
+
...values: unknown[]
|
|
197
|
+
): HtmlEscapedString | Promise<HtmlEscapedString> => {
|
|
198
|
+
const buffer: StringBufferWithCallbacks = [''] as StringBufferWithCallbacks
|
|
199
|
+
|
|
200
|
+
for (let i = 0, len = strings.length - 1; i < len; i++) {
|
|
201
|
+
buffer[0] += strings[i]
|
|
202
|
+
|
|
203
|
+
const children = Array.isArray(values[i])
|
|
204
|
+
? (values[i] as Array<unknown>).flat(Infinity)
|
|
205
|
+
: [values[i]]
|
|
206
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
207
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
208
|
+
const child = children[i] as any
|
|
209
|
+
if (typeof child === 'string') {
|
|
210
|
+
escapeToBuffer(child, buffer)
|
|
211
|
+
} else if (typeof child === 'number') {
|
|
212
|
+
;(buffer[0] as string) += child
|
|
213
|
+
} else if (
|
|
214
|
+
typeof child === 'boolean' ||
|
|
215
|
+
child === null ||
|
|
216
|
+
child === undefined
|
|
217
|
+
) {
|
|
218
|
+
continue
|
|
219
|
+
} else if (
|
|
220
|
+
typeof child === 'object' &&
|
|
221
|
+
(child as HtmlEscaped).isEscaped
|
|
222
|
+
) {
|
|
223
|
+
if ((child as HtmlEscapedString).callbacks) {
|
|
224
|
+
buffer.unshift('', child)
|
|
225
|
+
} else {
|
|
226
|
+
const tmp = child.toString()
|
|
227
|
+
if (tmp instanceof Promise) {
|
|
228
|
+
buffer.unshift('', tmp)
|
|
229
|
+
} else {
|
|
230
|
+
buffer[0] += tmp
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} else if (child instanceof Promise) {
|
|
234
|
+
buffer.unshift('', child)
|
|
235
|
+
} else {
|
|
236
|
+
escapeToBuffer(child.toString(), buffer)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
buffer[0] += strings.at(-1) as string
|
|
241
|
+
|
|
242
|
+
return buffer.length === 1
|
|
243
|
+
? 'callbacks' in buffer
|
|
244
|
+
? raw(resolveCallbackSync(raw(buffer[0], buffer.callbacks)))
|
|
245
|
+
: raw(buffer[0])
|
|
246
|
+
: stringBufferToString(buffer, buffer.callbacks)
|
|
247
|
+
}
|