@vyckr/tachyon 1.1.9 → 1.1.10

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.
@@ -0,0 +1,66 @@
1
+ export default async function(props) {
2
+
3
+ // imports
4
+
5
+ // script
6
+
7
+ if(props) props.split(';').map(prop => eval(prop))
8
+
9
+ const compRenders = new Map()
10
+
11
+ return async function(elemId, event, compId) {
12
+
13
+ const elemIds = new Map()
14
+
15
+ elemIds.set('@', new Map())
16
+ elemIds.set('id', new Map())
17
+ elemIds.set('bind', new Map())
18
+
19
+ const ty_generateId = (hash, source) => {
20
+
21
+ hash = compId ? `${hash}-${compId}` : hash
22
+
23
+ if(elemIds.get(source).has(hash)) {
24
+
25
+ const degree = elemIds.get(source).get(hash)
26
+
27
+ elemIds.get(source).set(hash, degree + 1)
28
+
29
+ return "ty-" + hash + "-" + degree
30
+ }
31
+
32
+ elemIds.get(source).set(hash, 1)
33
+
34
+ return "ty-" + hash + "-0"
35
+ }
36
+
37
+ const ty_invokeEvent = (hash, action) => {
38
+
39
+ if(elemId === ty_generateId(hash, '@')) {
40
+
41
+ if(event && !action.endsWith(')')) {
42
+ return `${action}('${event}')`
43
+ }
44
+ return action
45
+ }
46
+ return "''"
47
+ }
48
+
49
+ const ty_assignValue = (hash, variable) => {
50
+
51
+ if(elemId === ty_generateId(hash, 'bind') && event) {
52
+ return `${variable} = '${event.value}'`
53
+ }
54
+
55
+ return variable
56
+ }
57
+
58
+ let elements = '';
59
+
60
+ let render;
61
+
62
+ // inners
63
+
64
+ return elements
65
+ }
66
+ }
package/src/client/yon.ts CHANGED
@@ -20,12 +20,16 @@ export default class Yon {
20
20
 
21
21
  static async createStaticRoutes() {
22
22
 
23
- Router.reqRoutes["/render.js"] = {
24
- GET: async () => new Response(await Bun.file(`${import.meta.dir}/render.js`).bytes(), { headers: { 'Content-Type': 'application/javascript' } })
25
- }
23
+ const result = await Bun.build({
24
+ entrypoints: [`${import.meta.dir}/render.ts`, `${import.meta.dir}/hmr.ts`],
25
+ minify: true
26
+ })
26
27
 
27
- Router.reqRoutes["/hmr.js"] = {
28
- GET: async () => new Response(await Bun.file(`${import.meta.dir}/hmr.js`).bytes(), { headers: { 'Content-Type': 'application/javascript' } })
28
+ for(const output of result.outputs) {
29
+
30
+ Router.reqRoutes[output.path.replace('./', '/')] = {
31
+ GET: async () => new Response(output, { headers: { 'Content-Type': 'application/javascript' } })
32
+ }
29
33
  }
30
34
 
31
35
  Router.reqRoutes["/routes.json"] = {
@@ -54,158 +58,167 @@ export default class Yon {
54
58
  return { html, script: html.querySelectorAll('script')[0] }
55
59
  }
56
60
 
57
- private static parseHTML(elements: HTMLDivElement, imports: Map<string, Set<string>> = new Map<string, Set<string>>()) {
61
+ private static parseHTML(
62
+ elements: HTMLCollection,
63
+ imports: Map<string, Set<string>> = new Map<string, Set<string>>()
64
+ ): Array<{ static?: string; render?: string; element?: string }> {
65
+
66
+ const parsed: Array<{ static?: string; render?: string; element?: string }> = [];
67
+
68
+ const parseAttrs = (attrs: NamedNodeMap, hash: string) => Array.from(attrs).map(attr => {
69
+
70
+ if(attr.name.startsWith('@')) {
71
+ return `${attr.name}="` + "${eval(ty_invokeEvent('" + hash + "', '" + attr.value + "'))}" + '"'
72
+ }
73
+
74
+ if(attr.name === ":value") {
75
+ return `${attr.name.replace(':', '')}="` + "${eval(ty_assignValue('" + hash + "', '" + attr.value + "'))}" + '"'
76
+ }
77
+
78
+ return `${attr.name}="${attr.value}"`
79
+ })
58
80
 
59
- const parsed: { static?: string, render?: string, element?: string }[] = []
81
+ const interpolateText = (textContext: string) => textContext.replace(/\{([^{}]+)\}/g, '${$1}').replace(/\{\{([^{}]+)\}\}/g, '{${$1}}')
60
82
 
61
- for (const element of elements.children) {
83
+ for (const element of Array.from(elements)) {
62
84
 
63
- if(element.tagName !== "SCRIPT") {
85
+ if (element.tagName === "SCRIPT") {
86
+ continue; // Skip script tags as they're handled separately
87
+ }
64
88
 
65
- if(element.tagName.startsWith('TY-')) {
89
+ if(element.tagName === 'STYLE') {
90
+ element.innerHTML = `@scope { ${element.innerHTML} }`
91
+ parsed.push({ element: `\`${element.outerHTML}\`` })
92
+ continue
93
+ }
66
94
 
67
- const component = element.tagName.split('-')[1].toLowerCase()
68
-
69
- if(component === 'loop') {
70
- const attribute = element.attributes[0];
71
- if (attribute.name === ':for') parsed.push({ render: `for(${attribute.value}) {`})
72
- } else if(component === "logic") {
73
- const attribute = element.attributes[0]
74
- if (attribute.name === ':if') parsed.push({ render: `if(${attribute.value}) {`});
75
- if (attribute.name === ':else-if') parsed.push({ render: `else if(${attribute.value}) {`});
76
- if (attribute.name === ':else') parsed.push({ render: `else {`});
77
- } else {
78
-
79
- const exports: string[] = []
80
-
81
- const filepath = Yon.compMapping.get(component)
82
-
83
- if(filepath) {
84
-
85
- for(let i = 0; i < element.attributes.length; i++) {
86
-
87
- if(element.attributes[i].name.startsWith(':')) {
88
- const propName = element.attributes[i].name.slice(1)
89
- exports.push(`${propName} = ${"${" + element.attributes[i].value + "}"}`)
90
- } else {
91
- const propName = element.attributes[i].name
92
- exports.push(`${propName} = "${element.attributes[i].value}"`)
93
- }
94
- }
95
-
96
- if(imports.has(filepath)) {
97
-
98
- if(!imports.get(filepath)?.has(component)) {
99
- parsed.push({ static: `const { default: ${component} } = import('/components/${filepath}')`})
100
- imports.get(filepath)?.add(component)
101
- }
102
-
103
- } else {
104
-
105
- parsed.push({ static: `const { default: ${component} } = await import('/components/${filepath}')`})
106
- imports.set(filepath, new Set<string>([component]))
107
- }
108
-
109
- const hash = Bun.randomUUIDv7().split('-')[1]
110
-
111
- parsed.push({ static: `const comp_${hash} = await ${component}(\`${exports.join(';')}\`)`})
95
+ if(element.tagName.startsWith('TY') && !element.tagName.endsWith('LOOP') && !element.tagName.endsWith('LOGIC')) {
96
+
97
+ const component = element.tagName.split('-')[1].toLowerCase()
98
+
99
+ const filepath = Yon.compMapping.get(component)
100
+
101
+ if(filepath) {
112
102
 
113
- parsed.push({ render: `elements += "<div>"` })
103
+ if(imports.has(filepath)) {
114
104
 
115
- parsed.push({ render: `elements += comp_${hash}(execute && execute.compId === "ty-${hash}" ? execute : null).replaceAll('class="', 'class="ty-${hash} ')`})
116
-
117
- parsed.push({ render: `elements += "</div>"` })
105
+ if(!imports.get(filepath)?.has(component)) {
106
+ parsed.push({ static: `const { default: ${component} } = import('/components/${filepath}')`})
107
+ imports.get(filepath)?.add(component)
118
108
  }
109
+
110
+ } else {
111
+
112
+ parsed.push({ static: `const { default: ${component} } = await import('/components/${filepath}')`})
113
+ imports.set(filepath, new Set<string>([component]))
119
114
  }
120
-
121
- const temp = new JSDOM('').window.document.createElement('div');
122
- temp.innerHTML = element.innerHTML
123
-
124
- parsed.push(...this.parseHTML(temp, imports))
125
-
126
- if(component === "loop" || component === "logic") parsed.push({ render: '}'})
127
-
128
- } else if(element.tagName === "STYLE") {
129
-
130
- element.innerHTML = `@scope { ${element.innerHTML} }`
131
-
132
- parsed.push({ element: `\`${element.outerHTML}\`` })
133
-
115
+ }
116
+ }
117
+
118
+ const hash = Bun.randomUUIDv7().split('-')[3]
119
+
120
+ if(!element.id && !element.tagName.startsWith('TY-')) {
121
+ element.setAttribute(':id', "ty_generateId('" + hash + "', 'id')")
122
+ }
123
+
124
+ if(element.children.length > 0) {
125
+
126
+ const text = Array.from(element.childNodes).reduce((a, b) => {
127
+ return a + (b.nodeType === 3 ? b.textContent : '')
128
+ }, '')
129
+
130
+ parsed.push({ element: `\`<${element.tagName.toLowerCase()} ${parseAttrs(element.attributes, hash).join(" ")}>\`` })
131
+ if(text) parsed.push({ element: `\`${interpolateText(text)}\`` })
132
+ parsed.push(...this.parseHTML(element.children, imports))
133
+ parsed.push({ element: `\`</${element.tagName.toLowerCase()}>\`` })
134
+
135
+ } else {
136
+
137
+ if(element.outerHTML.includes('</')) {
138
+ parsed.push({ element: `\`<${element.tagName.toLowerCase()} ${parseAttrs(element.attributes, hash).join(" ")}>\`` })
139
+ if(element.textContent) parsed.push({ element: `\`${interpolateText(element.textContent)}\`` })
140
+ parsed.push({ element: `\`</${element.tagName.toLowerCase()}>\`` })
134
141
  } else {
135
-
136
- for(let i = 0; i < element.attributes.length; i++) {
137
-
138
- const attr = element.attributes[i]
139
-
140
- if(attr.name.startsWith(':')) {
141
-
142
- const attrName = attr.name.slice(1)
143
-
144
- element.removeAttribute(attr.name)
145
- element.setAttribute(attrName, "${" + attr.value + "}")
146
- }
147
- }
148
-
149
- parsed.push({ element: `\`${element.outerHTML}\`` })
142
+ parsed.push({ element: `\`<${element.tagName.toLowerCase()} ${parseAttrs(element.attributes, hash).join(" ")} />\`` })
150
143
  }
151
144
  }
152
145
  }
153
-
154
- return parsed
146
+
147
+ return parsed;
155
148
  }
156
149
 
157
- private static createJSData(html: { static?: string, render?: string, element?: string }[], scriptTag?: HTMLScriptElement) {
158
-
159
- const hash = Bun.randomUUIDv7().split('-')[3]
150
+ private static async createJSData(html: { static?: string, render?: string, element?: string }[], scriptTag?: HTMLScriptElement) {
160
151
 
161
- const outers: string[] = []
162
152
  const inners: string[] = []
153
+ const outers: string[] = []
163
154
 
164
155
  html.forEach(h => {
165
- if(h.static) outers.push(h.static)
166
156
  if(h.element) {
167
- const temp = new JSDOM('').window.document.createElement('div');
168
- temp.innerHTML = h.element
169
- if(temp.children[0].tagName !== 'STYLE') temp.children[0].classList.add(`ty-${hash}`)
170
- inners.push(`elements += ${temp.innerHTML}`)
157
+ if(h.element.includes('<ty-') || h.element.includes('</ty-')) {
158
+ inners.push(h.element)
159
+ } else inners.push(`elements+=${h.element}`)
171
160
  }
172
- if(h.render) inners.push(h.render)
161
+ if(h.static) outers.push(h.static)
173
162
  })
174
163
 
175
- return `
176
-
177
- export default async function(props) {
178
-
179
- ${scriptTag ? scriptTag.innerHTML : ''}
180
-
181
- ${outers.join('\n')}
182
-
183
- props?.split(';').map(exp => eval(exp))
184
-
185
- return function(execute) {
186
-
187
- if(execute) {
188
- const { classId, compId, func } = execute
189
- if(classId === "ty-${hash}" || compId === "ty-${hash}") {
190
- eval(func)
191
- }
192
- }
164
+ const tempFile = await Bun.file(`${import.meta.dir}/template.js`).text()
165
+
166
+ return tempFile.replaceAll('// imports', outers.join('\n'))
167
+ .replaceAll('// script', scriptTag?.innerHTML ?? '')
168
+ .replaceAll('// inners', inners.join('\n'))
169
+ .replaceAll(/`<ty-loop :for="(.*?)">`|`<\/ty-loop>`/g, (match, p1) => {
170
+ if(p1) return `for(${p1}) {`
171
+ else return '}'
172
+ })
173
+ .replaceAll(/`<ty-logic :if="(.*?)">`|`<\/ty-logic>`/g, (match, p1) => {
174
+ if(p1) return `if(${p1}) {`
175
+ else return '}'
176
+ })
177
+ .replaceAll(/`<ty-logic :else-if="(.*?)">`|`<\/ty-logic>`/g, (match, p1) => {
178
+ if(p1) return `else if(${p1}) {`
179
+ else return '}'
180
+ })
181
+ .replaceAll(/`<ty-logic :else="">`|`<\/ty-logic>`/g, (match, p1) => {
182
+ if(p1) return `else {`
183
+ else return '}'
184
+ })
185
+ .replaceAll(/:([^"]*)="([^"]*)"/g, '$1="${$2}"')
186
+ .replaceAll(/`<\/ty-(\w+)\s*>`/g, '')
187
+ .replaceAll(/`<ty-([a-zA-Z0-9-]+)(?:\s+([^>]*))>`/g, (match, component, atrributes) => {
188
+
189
+ const matches = atrributes.matchAll(/([a-zA-Z0-9-]+)="([^"]*)"/g)
190
+
191
+ const exports: string[] = []
192
+
193
+ for(const [_, key, value] of matches) {
194
+ exports.push(`${key}=${value}`)
195
+ }
196
+
197
+ const hash = Bun.randomUUIDv7().split('-')[3]
198
+
199
+ return `
200
+ elements += '<div>'
201
+
202
+ if(!compRenders.has('${hash}')) {
203
+ render = await ${component}(\`${exports.join(';')}\`)
204
+ elements += await render(elemId, event, '${hash}')
205
+ compRenders.set('${hash}', render)
206
+ } else {
207
+ render = compRenders.get('${hash}')
208
+ elements += await render(elemId, event, '${hash}')
209
+ }
193
210
 
194
- let elements = '';
195
-
196
- ${inners.join('\n')}
197
-
198
- return elements
199
- }
200
- }
201
- `
211
+ elements += '</div>'
212
+ `
213
+ })
214
+
202
215
  }
203
216
 
204
217
  private static async addToStatix(html: HTMLDivElement, script: HTMLScriptElement, route: string, dir: 'pages' | 'components') {
205
218
 
206
- const module = Yon.parseHTML(html)
219
+ const module = Yon.parseHTML(html.children)
207
220
 
208
- const jsData = Yon.createJSData(module, script)
221
+ const jsData = await Yon.createJSData(module, script)
209
222
 
210
223
  route = route.replace('.html', `.${script?.lang || 'js'}`)
211
224
 
package/src/serve.ts CHANGED
@@ -27,59 +27,59 @@ await configureRoutes()
27
27
 
28
28
  const server = Bun.serve({
29
29
  routes: Router.reqRoutes,
30
- // websocket: {
31
- // async open(ws: ServerWebSocket<WebSocketData>) {
30
+ websocket: {
31
+ async open(ws: ServerWebSocket<WebSocketData>) {
32
32
 
33
- // const { handler, path } = ws.data
33
+ const { handler, path } = ws.data
34
34
 
35
- // const proc = Bun.spawn({
36
- // cmd: [handler],
37
- // stdout: 'inherit',
38
- // stderr: "pipe",
39
- // stdin: "pipe"
40
- // })
35
+ const proc = Bun.spawn({
36
+ cmd: [handler],
37
+ stdout: 'inherit',
38
+ stderr: "pipe",
39
+ stdin: "pipe"
40
+ })
41
41
 
42
- // Tach.webSockets.set(ws, proc)
42
+ Tach.webSockets.set(ws, proc)
43
43
 
44
- // console.info(`WebSocket Connected - ${path} - ${proc.pid}`)
44
+ console.info(`WebSocket Connected - ${path} - ${proc.pid}`)
45
45
 
46
- // for await(const ev of watch(`/tmp`)) {
46
+ for await(const ev of watch(`/tmp`)) {
47
47
 
48
- // if(ev.filename === proc.pid.toString()) {
48
+ if(ev.filename === proc.pid.toString()) {
49
49
 
50
- // const status = ws.send(Bun.mmap(`/tmp/${proc.pid}`))
50
+ const status = ws.send(Bun.mmap(`/tmp/${proc.pid}`))
51
51
 
52
- // console.info(`WebSocket Message Sent - ${path} - ${proc.pid} - ${status} byte(s)`)
53
- // }
54
- // }
55
- // },
56
- // async message(ws: ServerWebSocket<WebSocketData>, message: string) {
52
+ console.info(`WebSocket Message Sent - ${path} - ${proc.pid} - ${status} byte(s)`)
53
+ }
54
+ }
55
+ },
56
+ async message(ws: ServerWebSocket<WebSocketData>, message: string) {
57
57
 
58
- // const proc = Tach.webSockets.get(ws)!
58
+ const proc = Tach.webSockets.get(ws)!
59
59
 
60
- // const { ctx, path } = ws.data
60
+ const { ctx, path } = ws.data
61
61
 
62
- // ctx.body = message
62
+ ctx.body = message
63
63
 
64
- // proc.stdin.write(JSON.stringify(ctx))
64
+ proc.stdin.write(JSON.stringify(ctx))
65
65
 
66
- // proc.stdin.flush()
66
+ proc.stdin.flush()
67
67
 
68
- // console.info(`WebSocket Message Received - ${path} - ${proc.pid} - ${message.length} byte(s)`)
69
- // },
70
- // close(ws, code, reason) {
68
+ console.info(`WebSocket Message Received - ${path} - ${proc.pid} - ${message.length} byte(s)`)
69
+ },
70
+ close(ws, code, reason) {
71
71
 
72
- // const { path } = ws.data
72
+ const { path } = ws.data
73
73
 
74
- // const proc = Tach.webSockets.get(ws)!
74
+ const proc = Tach.webSockets.get(ws)!
75
75
 
76
- // proc.stdin.end()
76
+ proc.stdin.end()
77
77
 
78
- // Tach.webSockets.delete(ws)
78
+ Tach.webSockets.delete(ws)
79
79
 
80
- // console.info(`WebSocket Disconnected - ${path} - ${proc.pid} - Code (${code}): ${reason}`)
81
- // },
82
- // },
80
+ console.info(`WebSocket Disconnected - ${path} - ${proc.pid} - Code (${code}): ${reason}`)
81
+ },
82
+ },
83
83
  port: process.env.PORT || 8080,
84
84
  hostname: process.env.HOSTNAME || '0.0.0.0',
85
85
  development: process.env.NODE_ENV === 'development'
@@ -1,13 +0,0 @@
1
- <script>
2
- let count;
3
- </script>
4
-
5
- <button @click="count++">+</button>
6
- <p>${count}</p>
7
- <button @click="count--">-</button>
8
-
9
- <style>
10
- p {
11
- color: blueviolet;
12
- }
13
- </style>