acrylblends 0.6.1 → 0.6.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 (217) hide show
  1. package/README.md +11 -6
  2. package/docs/framework/README.md +3 -2
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/api/presets.md +0 -3
  5. package/docs/framework/cordis/acryl-in-a-cordis-app.md +9 -0
  6. package/docs/framework/getting-started/basic.md +5 -4
  7. package/docs/framework/getting-started/desktop.md +41 -0
  8. package/docs/framework/guides/jsx-dom.md +0 -3
  9. package/docs/framework/guides/jsx.md +1 -4
  10. package/docs/framework/guides/middleware.md +1 -1
  11. package/docs/framework/helpers/cookie.md +1 -1
  12. package/docs/framework/helpers/css.md +0 -3
  13. package/docs/framework/helpers/dev.md +0 -3
  14. package/docs/framework/helpers/jwt.md +1 -1
  15. package/docs/framework/helpers/proxy.md +0 -3
  16. package/docs/framework/middleware/builtin/basic-auth.md +6 -6
  17. package/docs/framework/middleware/builtin/cache.md +0 -3
  18. package/docs/framework/middleware/builtin/combine.md +1 -1
  19. package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
  20. package/docs/framework/middleware/builtin/logger.md +1 -1
  21. package/docs/framework/middleware/builtin/mount.md +0 -3
  22. package/docs/framework/upstream.json +3 -3
  23. package/lib/accepts.d.ts +1 -1
  24. package/lib/acryl-base.d.ts +1 -1
  25. package/lib/adapter.d.ts +1 -1
  26. package/lib/{app-CmAYW1Al.d.ts → app-wFwpg-bt.d.ts} +1 -1
  27. package/lib/base-BpQy2Rk7.d.ts +783 -0
  28. package/lib/base-ddiVmiE7.js +721 -0
  29. package/lib/basic-auth.d.ts +1 -1
  30. package/lib/bearer-auth.d.ts +1 -1
  31. package/lib/body-limit.d.ts +1 -1
  32. package/lib/cache.d.ts +43 -0
  33. package/lib/cache.js +169 -0
  34. package/lib/client.d.ts +2 -2
  35. package/lib/combine.d.ts +1 -1
  36. package/lib/common-D8Z4JRCw.d.ts +46 -0
  37. package/lib/components-Ce5FRyHU.js +268 -0
  38. package/lib/components-DYZdxJIJ.js +24 -0
  39. package/lib/compress.d.ts +1 -1
  40. package/lib/conninfo.d.ts +2 -2
  41. package/lib/constants-BR9jM9BC.js +9 -0
  42. package/lib/{context-Bm7rI-oK.d.ts → context-DVQBjuns.d.ts} +1 -1
  43. package/lib/context-DxFdY_un.d.ts +250 -0
  44. package/lib/context-storage.d.ts +1 -1
  45. package/lib/{cookie-ClMaKDQf.d.ts → cookie-CCelEqky.d.ts} +1 -1
  46. package/lib/cookie.d.ts +3 -3
  47. package/lib/cors.d.ts +1 -1
  48. package/lib/csrf.d.ts +1 -1
  49. package/lib/css-D2jb7X8b.js +320 -0
  50. package/lib/css.d.ts +82 -0
  51. package/lib/css.js +134 -0
  52. package/lib/dev.d.ts +19 -0
  53. package/lib/dev.js +50 -0
  54. package/lib/etag.d.ts +1 -1
  55. package/lib/factory.d.ts +2 -2
  56. package/lib/hooks-Bq5q9IMl.js +762 -0
  57. package/lib/html-SllAe0YT.d.ts +46 -0
  58. package/lib/html.d.ts +1 -1
  59. package/lib/index-C850MeBA.d.ts +94 -0
  60. package/lib/{index-oOClm_Xk.d.ts → index-CUTfU69R.d.ts} +3 -3
  61. package/lib/{index-B-3F4wt2.d.ts → index-Cqcdluyn.d.ts} +2 -2
  62. package/lib/{index-UTBmM3GX.d.ts → index-CsvB-F9j.d.ts} +2 -2
  63. package/lib/index.d.ts +4 -4
  64. package/lib/ip-restriction.d.ts +2 -2
  65. package/lib/jsx/dom/client.d.ts +30 -0
  66. package/lib/jsx/dom/client.js +49 -0
  67. package/lib/jsx/dom/css.d.ts +84 -0
  68. package/lib/jsx/dom/css.js +2 -0
  69. package/lib/jsx/dom/jsx-dev-runtime.d.ts +3 -0
  70. package/lib/jsx/dom/jsx-dev-runtime.js +2 -0
  71. package/lib/jsx/dom/jsx-runtime.d.ts +3 -0
  72. package/lib/jsx/dom/jsx-runtime.js +2 -0
  73. package/lib/jsx/dom/server.d.ts +105 -0
  74. package/lib/jsx/dom/server.js +37 -0
  75. package/lib/jsx/dom.d.ts +5 -0
  76. package/lib/jsx/dom.js +74 -0
  77. package/lib/jsx/jsx-dev-runtime.d.ts +6 -0
  78. package/lib/jsx/jsx-dev-runtime.js +14 -0
  79. package/lib/jsx/jsx-runtime.d.ts +10 -0
  80. package/lib/jsx/jsx-runtime.js +30 -0
  81. package/lib/jsx/streaming.d.ts +2 -0
  82. package/lib/jsx/streaming.js +2 -0
  83. package/lib/jsx-dev-runtime-B22O-Npk.d.ts +7 -0
  84. package/lib/jsx-dev-runtime-kAhR_4C7.js +354 -0
  85. package/lib/jsx-runtime-BVVgDSdq.d.ts +1 -0
  86. package/lib/jsx.d.ts +3 -0
  87. package/lib/jsx.js +47 -0
  88. package/lib/jwk.d.ts +4 -4
  89. package/lib/{jwt-Dg493Tai.d.ts → jwt-BARhotDz.d.ts} +1 -1
  90. package/lib/jwt.d.ts +4 -4
  91. package/lib/language.d.ts +1 -1
  92. package/lib/linear-router-C3FPib6h.js +96 -0
  93. package/lib/logger.d.ts +1 -1
  94. package/lib/loopback-only.d.ts +1 -1
  95. package/lib/method-not-allowed.d.ts +2 -2
  96. package/lib/method-override.d.ts +2 -2
  97. package/lib/mount.d.ts +44 -0
  98. package/lib/mount.js +67 -0
  99. package/lib/node-server/conninfo.d.ts +1 -1
  100. package/lib/node-server/serve-static.d.ts +1 -1
  101. package/lib/node-server/serve-static.js +1 -1
  102. package/lib/node-server.d.ts +1 -1
  103. package/lib/node-server.js +1 -1
  104. package/lib/pattern-router-HZxjDGEQ.js +41 -0
  105. package/lib/powered-by.d.ts +1 -1
  106. package/lib/pretty-json.d.ts +1 -1
  107. package/lib/proxy.d.ts +72 -0
  108. package/lib/proxy.js +121 -0
  109. package/lib/quick.d.ts +8 -0
  110. package/lib/quick.js +17 -0
  111. package/lib/request-id.d.ts +1 -1
  112. package/lib/request.d.ts +1 -1
  113. package/lib/route.d.ts +1 -1
  114. package/lib/router/linear-router.js +1 -95
  115. package/lib/router/pattern-router.js +1 -40
  116. package/lib/schema-validator.d.ts +1 -1
  117. package/lib/secure-headers.d.ts +1 -1
  118. package/lib/{serve-static-Dw_m6KxR.js → serve-static-Cw23shXv.js} +1 -0
  119. package/lib/serve-static.d.ts +1 -1
  120. package/lib/streaming.d.ts +1 -1
  121. package/lib/testing.d.ts +4 -4
  122. package/lib/timeout.d.ts +1 -1
  123. package/lib/timing.d.ts +1 -1
  124. package/lib/tiny.d.ts +8 -0
  125. package/lib/tiny.js +15 -0
  126. package/lib/trailing-slash.d.ts +1 -1
  127. package/lib/{types-CHesD1KG.d.ts → types-CQiGmsWW.d.ts} +3 -3
  128. package/lib/{types-CwrQjlaM.d.ts → types-Lqx5BxQF.d.ts} +10 -1
  129. package/lib/{types-CDO6I3B0.d.ts → types-nEL8VPDC.d.ts} +1 -1
  130. package/lib/types.d.ts +1 -1
  131. package/lib/utils/body.d.ts +1 -1
  132. package/lib/utils/cookie.d.ts +1 -1
  133. package/lib/utils/crypto.d.ts +1 -1
  134. package/lib/utils/html.d.ts +1 -45
  135. package/lib/utils/ipaddr.d.ts +1 -1
  136. package/lib/utils/jwt.d.ts +1 -1
  137. package/lib/utils/types.d.ts +2 -2
  138. package/lib/validator.d.ts +2 -2
  139. package/lib/ws.d.ts +1 -1
  140. package/package.json +69 -1
  141. package/plugins/acryl-inspect/upstream.json +1 -1
  142. package/plugins/acryl-node-server/upstream.json +1 -1
  143. package/plugins/acryl-router/src/core/helper/css/common.case.test.tsx +506 -0
  144. package/plugins/acryl-router/src/core/helper/css/common.ts +337 -0
  145. package/plugins/acryl-router/src/core/helper/css/index.test.tsx +678 -0
  146. package/plugins/acryl-router/src/core/helper/css/index.ts +262 -0
  147. package/plugins/acryl-router/src/core/helper/dev/index.test.ts +181 -0
  148. package/plugins/acryl-router/src/core/helper/dev/index.ts +79 -0
  149. package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +356 -0
  150. package/plugins/acryl-router/src/core/helper/proxy/index.ts +203 -0
  151. package/plugins/acryl-router/src/core/helper/streaming/sse.test.tsx +557 -0
  152. package/plugins/acryl-router/src/core/jsx/base.test.tsx +97 -0
  153. package/plugins/acryl-router/src/core/jsx/base.ts +490 -0
  154. package/plugins/acryl-router/src/core/jsx/children.test.ts +52 -0
  155. package/plugins/acryl-router/src/core/jsx/children.ts +20 -0
  156. package/plugins/acryl-router/src/core/jsx/components.test.tsx +936 -0
  157. package/plugins/acryl-router/src/core/jsx/components.ts +257 -0
  158. package/plugins/acryl-router/src/core/jsx/constants.ts +6 -0
  159. package/plugins/acryl-router/src/core/jsx/context-isolation.test.ts +655 -0
  160. package/plugins/acryl-router/src/core/jsx/context.ts +266 -0
  161. package/plugins/acryl-router/src/core/jsx/dom/client.test.tsx +128 -0
  162. package/plugins/acryl-router/src/core/jsx/dom/client.ts +89 -0
  163. package/plugins/acryl-router/src/core/jsx/dom/components.test.tsx +330 -0
  164. package/plugins/acryl-router/src/core/jsx/dom/components.ts +39 -0
  165. package/plugins/acryl-router/src/core/jsx/dom/context.test.tsx +184 -0
  166. package/plugins/acryl-router/src/core/jsx/dom/context.ts +52 -0
  167. package/plugins/acryl-router/src/core/jsx/dom/css.test.tsx +149 -0
  168. package/plugins/acryl-router/src/core/jsx/dom/css.ts +263 -0
  169. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.test.tsx +172 -0
  170. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.ts +91 -0
  171. package/plugins/acryl-router/src/core/jsx/dom/index.test.tsx +3681 -0
  172. package/plugins/acryl-router/src/core/jsx/dom/index.ts +170 -0
  173. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.test.tsx +1344 -0
  174. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.ts +438 -0
  175. package/plugins/acryl-router/src/core/jsx/dom/jsx-dev-runtime.ts +23 -0
  176. package/plugins/acryl-router/src/core/jsx/dom/jsx-runtime.ts +8 -0
  177. package/plugins/acryl-router/src/core/jsx/dom/render.ts +879 -0
  178. package/plugins/acryl-router/src/core/jsx/dom/server.test.tsx +199 -0
  179. package/plugins/acryl-router/src/core/jsx/dom/server.ts +76 -0
  180. package/plugins/acryl-router/src/core/jsx/dom/utils.ts +7 -0
  181. package/plugins/acryl-router/src/core/jsx/hooks/dom.test.tsx +859 -0
  182. package/plugins/acryl-router/src/core/jsx/hooks/index.ts +437 -0
  183. package/plugins/acryl-router/src/core/jsx/hooks/string.test.tsx +40 -0
  184. package/plugins/acryl-router/src/core/jsx/index.test.tsx +1744 -0
  185. package/plugins/acryl-router/src/core/jsx/index.ts +115 -0
  186. package/plugins/acryl-router/src/core/jsx/intrinsic-element/common.ts +23 -0
  187. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.test.tsx +666 -0
  188. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.ts +210 -0
  189. package/plugins/acryl-router/src/core/jsx/intrinsic-elements.ts +938 -0
  190. package/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts +26 -0
  191. package/plugins/acryl-router/src/core/jsx/jsx-runtime.test.tsx +85 -0
  192. package/plugins/acryl-router/src/core/jsx/jsx-runtime.ts +51 -0
  193. package/plugins/acryl-router/src/core/jsx/streaming.test.tsx +1281 -0
  194. package/plugins/acryl-router/src/core/jsx/streaming.ts +231 -0
  195. package/plugins/acryl-router/src/core/jsx/types.ts +41 -0
  196. package/plugins/acryl-router/src/core/jsx/utils.test.ts +366 -0
  197. package/plugins/acryl-router/src/core/jsx/utils.ts +202 -0
  198. package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +1211 -0
  199. package/plugins/acryl-router/src/core/middleware/cache/index.ts +323 -0
  200. package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +334 -0
  201. package/plugins/acryl-router/src/core/middleware/mount/index.ts +108 -0
  202. package/plugins/acryl-router/src/core/preset/quick.test.ts +42 -0
  203. package/plugins/acryl-router/src/core/preset/quick.ts +24 -0
  204. package/plugins/acryl-router/src/core/preset/tiny.test.ts +42 -0
  205. package/plugins/acryl-router/src/core/preset/tiny.ts +20 -0
  206. package/plugins/acryl-router/src/core/utils/types.ts +9 -0
  207. package/plugins/acryl-router/src/helpers/index.ts +3 -0
  208. package/plugins/acryl-router/src/middleware/index.ts +2 -0
  209. package/plugins/acryl-router/src/service.ts +22 -5
  210. package/plugins/acryl-router/tests/jsx.spec.tsx +63 -0
  211. package/plugins/acryl-router/upstream.json +3 -3
  212. package/plugins/acryl-router-http/upstream.json +1 -1
  213. package/plugins/acryl-state/upstream.json +1 -1
  214. package/plugins/desktop/upstream.json +1 -1
  215. package/plugins/desktop-web/upstream.json +1 -1
  216. package/plugins/save/plugin.json +1 -1
  217. package/templates/todo/upstream.json +1 -1
@@ -0,0 +1,262 @@
1
+ /**
2
+ * @module
3
+ * css Helper for Acryl.
4
+ */
5
+
6
+ import { raw } from '../html/index.ts'
7
+ import { DOM_RENDERER } from '../../jsx/constants.ts'
8
+ import { createCssJsxDomObjects } from '../../jsx/dom/css.ts'
9
+ import { escapeToBuffer } from '../../utils/html.ts'
10
+ import type { HtmlEscapedCallback, HtmlEscapedString } from '../../utils/html.ts'
11
+ import type {
12
+ ClassNameSlug,
13
+ CssClassName as CssClassNameCommon,
14
+ CssVariableType,
15
+ OnInvalidSlug,
16
+ } from './common.ts'
17
+ import {
18
+ CLASS_NAME,
19
+ DEFAULT_STYLE_ID,
20
+ PSEUDO_GLOBAL_SELECTOR,
21
+ SELECTOR,
22
+ SELECTORS,
23
+ STYLE_STRING,
24
+ cssCommon,
25
+ cxCommon,
26
+ keyframesCommon,
27
+ viewTransitionCommon,
28
+ } from './common.ts'
29
+ export { rawCssString } from './common.ts'
30
+ export type { ClassNameSlug, OnInvalidSlug } from './common.ts'
31
+
32
+ type CssClassName = HtmlEscapedString & CssClassNameCommon
33
+
34
+ type usedClassNameData = [
35
+ Record<string, string>, // class name to add
36
+ Record<string, true>, // class name already added
37
+ ]
38
+
39
+ interface CssType {
40
+ (strings: TemplateStringsArray, ...values: CssVariableType[]): Promise<string>
41
+ }
42
+
43
+ interface CxType {
44
+ (
45
+ ...args: (CssClassName | Promise<string> | string | boolean | null | undefined)[]
46
+ ): Promise<string>
47
+ }
48
+
49
+ interface KeyframesType {
50
+ (strings: TemplateStringsArray, ...values: CssVariableType[]): CssClassNameCommon
51
+ }
52
+
53
+ interface ViewTransitionType {
54
+ (strings: TemplateStringsArray, ...values: CssVariableType[]): Promise<string>
55
+ (content: Promise<string>): Promise<string>
56
+ (): Promise<string>
57
+ }
58
+
59
+ interface StyleType {
60
+ (args?: { children?: Promise<string>; nonce?: string }): HtmlEscapedString
61
+ }
62
+
63
+ /**
64
+ * @experimental
65
+ * `createCssContext` is an experimental feature.
66
+ * The API might be changed.
67
+ *
68
+ * @param options.id - The ID for the style element
69
+ * @param options.classNameSlug - Optional function to customize generated CSS class names
70
+ * @param options.onInvalidSlug - Optional callback function called when an invalid slug is returned from ClassNameSlug
71
+ */
72
+ export const createCssContext = ({
73
+ id,
74
+ classNameSlug,
75
+ onInvalidSlug,
76
+ }: {
77
+ id: Readonly<string>
78
+ classNameSlug?: ClassNameSlug
79
+ onInvalidSlug?: OnInvalidSlug
80
+ }): DefaultContextType => {
81
+ const [cssJsxDomObject, StyleRenderToDom] = createCssJsxDomObjects({ id })
82
+
83
+ const contextMap: WeakMap<object, usedClassNameData> = new WeakMap()
84
+ const nonceMap: WeakMap<object, string | undefined> = new WeakMap()
85
+
86
+ const replaceStyleRe = new RegExp(`(<style id="${id}"(?: nonce="[^"]*")?>.*?)(</style>)`, 's')
87
+
88
+ const newCssClassNameObject = (cssClassName: CssClassNameCommon): Promise<string> => {
89
+ const appendStyle: HtmlEscapedCallback = ({ buffer, context }): Promise<string> | undefined => {
90
+ const [toAdd, added] = contextMap.get(context) as usedClassNameData
91
+ const names = Object.keys(toAdd)
92
+
93
+ if (!names.length) {
94
+ return
95
+ }
96
+
97
+ let stylesStr = ''
98
+ names.forEach((className) => {
99
+ added[className] = true
100
+ stylesStr += className.startsWith(PSEUDO_GLOBAL_SELECTOR)
101
+ ? toAdd[className]
102
+ : `${className[0] === '@' ? '' : '.'}${className}{${toAdd[className]}}`
103
+ })
104
+ contextMap.set(context, [{}, added])
105
+
106
+ if (buffer && replaceStyleRe.test(buffer[0])) {
107
+ buffer[0] = buffer[0].replace(replaceStyleRe, (_, pre, post) => `${pre}${stylesStr}${post}`)
108
+ return
109
+ }
110
+
111
+ const nonce = nonceMap.get(context)
112
+ const appendStyleScript = `<script${
113
+ nonce ? ` nonce="${nonce}"` : ''
114
+ }>document.querySelector('#${id}').textContent+=${JSON.stringify(stylesStr)}</script>`
115
+
116
+ if (buffer) {
117
+ buffer[0] = `${appendStyleScript}${buffer[0]}`
118
+ return
119
+ }
120
+
121
+ return Promise.resolve(appendStyleScript)
122
+ }
123
+
124
+ const addClassNameToContext: HtmlEscapedCallback = ({ context }) => {
125
+ if (!contextMap.has(context)) {
126
+ contextMap.set(context, [{}, {}])
127
+ }
128
+ const [toAdd, added] = contextMap.get(context) as usedClassNameData
129
+ let allAdded = true
130
+ if (!added[cssClassName[SELECTOR]]) {
131
+ allAdded = false
132
+ toAdd[cssClassName[SELECTOR]] = cssClassName[STYLE_STRING]
133
+ }
134
+ cssClassName[SELECTORS].forEach(
135
+ ({ [CLASS_NAME]: className, [STYLE_STRING]: styleString }) => {
136
+ if (!added[className]) {
137
+ allAdded = false
138
+ toAdd[className] = styleString
139
+ }
140
+ }
141
+ )
142
+ if (allAdded) {
143
+ return
144
+ }
145
+
146
+ return Promise.resolve(raw('', [appendStyle]))
147
+ }
148
+
149
+ // external class names from cx() are untrusted but the result is marked isEscaped,
150
+ // so escape it here. skip the buffer when there is nothing to escape.
151
+ const rawClassName = cssClassName[CLASS_NAME]
152
+ let escapedClassName = rawClassName
153
+ if (/[&<>'"]/.test(rawClassName)) {
154
+ const escapedBuffer: [string] = ['']
155
+ escapeToBuffer(rawClassName, escapedBuffer)
156
+ escapedClassName = escapedBuffer[0]
157
+ }
158
+ const className = new String(escapedClassName) as CssClassName
159
+ Object.assign(className, cssClassName)
160
+ ;(className as HtmlEscapedString).isEscaped = true
161
+ ;(className as HtmlEscapedString).callbacks = [addClassNameToContext]
162
+ const promise = Promise.resolve(className)
163
+ Object.assign(promise, cssClassName)
164
+
165
+ promise.toString = cssJsxDomObject.toString
166
+ return promise
167
+ }
168
+
169
+ const css: CssType = (strings, ...values) => {
170
+ return newCssClassNameObject(cssCommon(strings, values, classNameSlug, onInvalidSlug))
171
+ }
172
+
173
+ const cx: CxType = (...args) => {
174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
175
+ args = cxCommon(args as any) as any
176
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
177
+ return css(Array(args.length).fill('') as any, ...args)
178
+ }
179
+
180
+ const keyframes: KeyframesType = (strings, ...values) =>
181
+ keyframesCommon(strings, values, classNameSlug, onInvalidSlug)
182
+
183
+ const viewTransition: ViewTransitionType = ((
184
+ strings: TemplateStringsArray | Promise<string> | undefined,
185
+ ...values: CssVariableType[]
186
+ ) => {
187
+ return newCssClassNameObject(
188
+ viewTransitionCommon(strings as any, values, classNameSlug, onInvalidSlug) // eslint-disable-line @typescript-eslint/no-explicit-any
189
+ )
190
+ }) as ViewTransitionType
191
+
192
+ const Style: StyleType = ({ children, nonce } = {}) =>
193
+ raw(
194
+ `<style id="${id}"${nonce ? ` nonce="${nonce}"` : ''}>${
195
+ children ? (children as unknown as CssClassName)[STYLE_STRING] : ''
196
+ }</style>`,
197
+ [
198
+ ({ context }) => {
199
+ nonceMap.set(context, nonce)
200
+ return undefined
201
+ },
202
+ ]
203
+ )
204
+
205
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
206
+ ;(Style as any)[DOM_RENDERER] = StyleRenderToDom
207
+
208
+ return {
209
+ css,
210
+ cx,
211
+ keyframes,
212
+ viewTransition: viewTransition as ViewTransitionType,
213
+ Style,
214
+ }
215
+ }
216
+
217
+ interface DefaultContextType {
218
+ css: CssType
219
+ cx: CxType
220
+ keyframes: KeyframesType
221
+ viewTransition: ViewTransitionType
222
+ Style: StyleType
223
+ }
224
+
225
+ const defaultContext: DefaultContextType = createCssContext({
226
+ id: DEFAULT_STYLE_ID,
227
+ })
228
+
229
+ /**
230
+ * @experimental
231
+ * `css` is an experimental feature.
232
+ * The API might be changed.
233
+ */
234
+ export const css = defaultContext.css
235
+
236
+ /**
237
+ * @experimental
238
+ * `cx` is an experimental feature.
239
+ * The API might be changed.
240
+ */
241
+ export const cx = defaultContext.cx
242
+
243
+ /**
244
+ * @experimental
245
+ * `keyframes` is an experimental feature.
246
+ * The API might be changed.
247
+ */
248
+ export const keyframes = defaultContext.keyframes
249
+
250
+ /**
251
+ * @experimental
252
+ * `viewTransition` is an experimental feature.
253
+ * The API might be changed.
254
+ */
255
+ export const viewTransition = defaultContext.viewTransition
256
+
257
+ /**
258
+ * @experimental
259
+ * `Style` is an experimental feature.
260
+ * The API might be changed.
261
+ */
262
+ export const Style = defaultContext.Style
@@ -0,0 +1,181 @@
1
+ import { getRouterName, inspectRoutes, showRoutes } from './index.ts'
2
+ import { Acryl } from '../../app.ts'
3
+ import { RegExpRouter } from '../../router/reg-exp-router/index.ts'
4
+ import type { Handler, MiddlewareHandler } from '../../types.ts'
5
+
6
+ const namedMiddleware: MiddlewareHandler = (_, next) => next()
7
+ const namedHandler: Handler = (c) => c.text('hi')
8
+ const app = new Acryl()
9
+ .use('*', (_c, next) => next())
10
+ .get(
11
+ '/',
12
+ (_, next) => next(),
13
+ (c) => c.text('hi')
14
+ )
15
+ .get('/named', namedMiddleware, namedHandler)
16
+ .post('/', (c) => c.text('hi'))
17
+ .put('/', (c) => c.text('hi'))
18
+ .patch('/', (c) => c.text('hi'))
19
+ .delete('/', (c) => c.text('hi'))
20
+ .options('/', (c) => c.text('hi'))
21
+ .get('/static', () => new Response('hi'))
22
+
23
+ describe('inspectRoutes()', () => {
24
+ it('should return correct data', async () => {
25
+ expect(inspectRoutes(app)).toEqual([
26
+ { path: '/*', method: 'ALL', name: '[middleware]', isMiddleware: true },
27
+ { path: '/', method: 'GET', name: '[middleware]', isMiddleware: true },
28
+ { path: '/', method: 'GET', name: '[handler]', isMiddleware: false },
29
+ { path: '/named', method: 'GET', name: 'namedMiddleware', isMiddleware: true },
30
+ { path: '/named', method: 'GET', name: 'namedHandler', isMiddleware: false },
31
+ { path: '/', method: 'POST', name: '[handler]', isMiddleware: false },
32
+ { path: '/', method: 'PUT', name: '[handler]', isMiddleware: false },
33
+ { path: '/', method: 'PATCH', name: '[handler]', isMiddleware: false },
34
+ { path: '/', method: 'DELETE', name: '[handler]', isMiddleware: false },
35
+ { path: '/', method: 'OPTIONS', name: '[handler]', isMiddleware: false },
36
+ { path: '/static', method: 'GET', name: '[handler]', isMiddleware: false },
37
+ ])
38
+ })
39
+
40
+ it('should return [handler] also for sub app', async () => {
41
+ const subApp = new Acryl()
42
+
43
+ subApp.get('/', (c) => c.json(0))
44
+ subApp.onError((_, c) => c.json(0))
45
+
46
+ const mainApp = new Acryl()
47
+ mainApp.route('/', subApp)
48
+ expect(inspectRoutes(mainApp)).toEqual([
49
+ {
50
+ isMiddleware: false,
51
+ method: 'GET',
52
+ name: '[handler]',
53
+ path: '/',
54
+ },
55
+ ])
56
+ })
57
+ })
58
+
59
+ describe('showRoutes()', () => {
60
+ let logs: string[] = []
61
+
62
+ let originalLog: typeof console.log
63
+ beforeAll(() => {
64
+ originalLog = console.log
65
+ console.log = (...args) => logs.push(...args)
66
+ })
67
+ afterAll(() => {
68
+ console.log = originalLog
69
+ })
70
+
71
+ beforeEach(() => {
72
+ logs = []
73
+ })
74
+ it('should render simple output', async () => {
75
+ showRoutes(app)
76
+ expect(logs).toEqual([
77
+ '\x1b[32mGET\x1b[0m /',
78
+ '\x1b[32mGET\x1b[0m /named',
79
+ '\x1b[32mPOST\x1b[0m /',
80
+ '\x1b[32mPUT\x1b[0m /',
81
+ '\x1b[32mPATCH\x1b[0m /',
82
+ '\x1b[32mDELETE\x1b[0m /',
83
+ '\x1b[32mOPTIONS\x1b[0m /',
84
+ '\x1b[32mGET\x1b[0m /static',
85
+ ])
86
+ })
87
+
88
+ it('should render output includes handlers and middlewares', async () => {
89
+ showRoutes(app, { verbose: true })
90
+ expect(logs).toEqual([
91
+ '\x1b[32mALL\x1b[0m /*',
92
+ ' [middleware]',
93
+ '\x1b[32mGET\x1b[0m /',
94
+ ' [middleware]',
95
+ ' [handler]',
96
+ '\x1b[32mGET\x1b[0m /named',
97
+ ' namedMiddleware',
98
+ ' namedHandler',
99
+ '\x1b[32mPOST\x1b[0m /',
100
+ ' [handler]',
101
+ '\x1b[32mPUT\x1b[0m /',
102
+ ' [handler]',
103
+ '\x1b[32mPATCH\x1b[0m /',
104
+ ' [handler]',
105
+ '\x1b[32mDELETE\x1b[0m /',
106
+ ' [handler]',
107
+ '\x1b[32mOPTIONS\x1b[0m /',
108
+ ' [handler]',
109
+ '\x1b[32mGET\x1b[0m /static',
110
+ ' [handler]',
111
+ ])
112
+ })
113
+
114
+ it('should render not colorized output', async () => {
115
+ showRoutes(app, { colorize: false })
116
+ expect(logs).toEqual([
117
+ 'GET /',
118
+ 'GET /named',
119
+ 'POST /',
120
+ 'PUT /',
121
+ 'PATCH /',
122
+ 'DELETE /',
123
+ 'OPTIONS /',
124
+ 'GET /static',
125
+ ])
126
+ })
127
+ })
128
+
129
+ describe('showRoutes() in NO_COLOR', () => {
130
+ let logs: string[] = []
131
+
132
+ let originalLog: typeof console.log
133
+ beforeAll(() => {
134
+ vi.stubEnv('NO_COLOR', '1')
135
+ originalLog = console.log
136
+ console.log = (...args) => logs.push(...args)
137
+ })
138
+ afterAll(() => {
139
+ vi.unstubAllEnvs()
140
+ console.log = originalLog
141
+ })
142
+
143
+ beforeEach(() => {
144
+ logs = []
145
+ })
146
+ it('should render not colorized output', async () => {
147
+ showRoutes(app)
148
+ expect(logs).toEqual([
149
+ 'GET /',
150
+ 'GET /named',
151
+ 'POST /',
152
+ 'PUT /',
153
+ 'PATCH /',
154
+ 'DELETE /',
155
+ 'OPTIONS /',
156
+ 'GET /static',
157
+ ])
158
+ })
159
+ it('should render colorized output if colorize: true', async () => {
160
+ showRoutes(app, { colorize: true })
161
+ expect(logs).toEqual([
162
+ '\x1b[32mGET\x1b[0m /',
163
+ '\x1b[32mGET\x1b[0m /named',
164
+ '\x1b[32mPOST\x1b[0m /',
165
+ '\x1b[32mPUT\x1b[0m /',
166
+ '\x1b[32mPATCH\x1b[0m /',
167
+ '\x1b[32mDELETE\x1b[0m /',
168
+ '\x1b[32mOPTIONS\x1b[0m /',
169
+ '\x1b[32mGET\x1b[0m /static',
170
+ ])
171
+ })
172
+ })
173
+
174
+ describe('getRouterName()', () => {
175
+ it('Should return the correct router name', async () => {
176
+ const app = new Acryl({
177
+ router: new RegExpRouter(),
178
+ })
179
+ expect(getRouterName(app)).toBe('RegExpRouter')
180
+ })
181
+ })
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @module
3
+ * Dev Helper for Acryl.
4
+ */
5
+
6
+ import type { Acryl } from '../../app.ts'
7
+ import type { Env, RouterRoute } from '../../types.ts'
8
+ import { getColorEnabled } from '../../utils/color.ts'
9
+ import { findTargetHandler, isMiddleware } from '../../utils/handler.ts'
10
+
11
+ interface ShowRoutesOptions {
12
+ verbose?: boolean
13
+ colorize?: boolean
14
+ }
15
+
16
+ interface RouteData {
17
+ path: string
18
+ method: string
19
+ name: string
20
+ isMiddleware: boolean
21
+ }
22
+
23
+ const handlerName = (handler: Function): string => {
24
+ return handler.name || (isMiddleware(handler) ? '[middleware]' : '[handler]')
25
+ }
26
+
27
+ export const inspectRoutes = <E extends Env>(acryl: Acryl<E>): RouteData[] => {
28
+ return acryl.routes.map(({ path, method, handler }: RouterRoute) => {
29
+ const targetHandler = findTargetHandler(handler)
30
+ return {
31
+ path,
32
+ method,
33
+ name: handlerName(targetHandler),
34
+ isMiddleware: isMiddleware(targetHandler),
35
+ }
36
+ })
37
+ }
38
+
39
+ export const showRoutes = <E extends Env>(acryl: Acryl<E>, opts?: ShowRoutesOptions): void => {
40
+ const colorEnabled = opts?.colorize ?? getColorEnabled()
41
+ const routeData: Record<string, RouteData[]> = {}
42
+ let maxMethodLength = 0
43
+ let maxPathLength = 0
44
+
45
+ inspectRoutes(acryl)
46
+ .filter(({ isMiddleware }) => opts?.verbose || !isMiddleware)
47
+ .map((route) => {
48
+ const key = `${route.method}-${route.path}`
49
+ ;(routeData[key] ||= []).push(route)
50
+ if (routeData[key].length > 1) {
51
+ return
52
+ }
53
+ maxMethodLength = Math.max(maxMethodLength, route.method.length)
54
+ maxPathLength = Math.max(maxPathLength, route.path.length)
55
+ return { method: route.method, path: route.path, routes: routeData[key] }
56
+ })
57
+ .forEach((data) => {
58
+ if (!data) {
59
+ return
60
+ }
61
+ const { method, path, routes } = data
62
+
63
+ const methodStr = colorEnabled ? `\x1b[32m${method}\x1b[0m` : method
64
+ console.log(`${methodStr} ${' '.repeat(maxMethodLength - method.length)} ${path}`)
65
+
66
+ if (!opts?.verbose) {
67
+ return
68
+ }
69
+
70
+ routes.forEach(({ name }) => {
71
+ console.log(`${' '.repeat(maxMethodLength + 3)} ${name}`)
72
+ })
73
+ })
74
+ }
75
+
76
+ export const getRouterName = <E extends Env>(app: Acryl<E>): string => {
77
+ app.router.match('GET', '/')
78
+ return app.router.name
79
+ }