@typed/template 0.2.0 → 0.3.0

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 (213) hide show
  1. package/dist/cjs/Directive.js +1 -1
  2. package/dist/cjs/Directive.js.map +1 -1
  3. package/dist/cjs/ElementRef.js +23 -13
  4. package/dist/cjs/ElementRef.js.map +1 -1
  5. package/dist/cjs/ElementSource.js +16 -18
  6. package/dist/cjs/ElementSource.js.map +1 -1
  7. package/dist/cjs/EventHandler.js +1 -1
  8. package/dist/cjs/EventHandler.js.map +1 -1
  9. package/dist/cjs/Html.js +31 -32
  10. package/dist/cjs/Html.js.map +1 -1
  11. package/dist/cjs/HtmlChunk.js +4 -1
  12. package/dist/cjs/HtmlChunk.js.map +1 -1
  13. package/dist/cjs/Hydrate.js +1 -1
  14. package/dist/cjs/Hydrate.js.map +1 -1
  15. package/dist/cjs/Many.js +14 -13
  16. package/dist/cjs/Many.js.map +1 -1
  17. package/dist/cjs/Parser.js +11 -323
  18. package/dist/cjs/Parser.js.map +1 -1
  19. package/dist/cjs/Placeholder.js +3 -3
  20. package/dist/cjs/Placeholder.js.map +1 -1
  21. package/dist/cjs/Platform.js +4 -4
  22. package/dist/cjs/Platform.js.map +1 -1
  23. package/dist/cjs/Render.js +1 -1
  24. package/dist/cjs/Render.js.map +1 -1
  25. package/dist/cjs/RenderContext.js +48 -27
  26. package/dist/cjs/RenderContext.js.map +1 -1
  27. package/dist/cjs/RenderTemplate.js +2 -17
  28. package/dist/cjs/RenderTemplate.js.map +1 -1
  29. package/dist/cjs/Template.js +27 -1
  30. package/dist/cjs/Template.js.map +1 -1
  31. package/dist/cjs/TemplateInstance.js +2 -2
  32. package/dist/cjs/TemplateInstance.js.map +1 -1
  33. package/dist/cjs/Test.js +20 -7
  34. package/dist/cjs/Test.js.map +1 -1
  35. package/dist/cjs/index.js +0 -12
  36. package/dist/cjs/index.js.map +1 -1
  37. package/dist/cjs/internal/EventSource.js +95 -0
  38. package/dist/cjs/internal/EventSource.js.map +1 -0
  39. package/dist/cjs/internal/browser.js +11 -11
  40. package/dist/cjs/internal/browser.js.map +1 -1
  41. package/dist/cjs/internal/hydrate.js +49 -50
  42. package/dist/cjs/internal/hydrate.js.map +1 -1
  43. package/dist/cjs/internal/indexRefCounter.js +49 -2
  44. package/dist/cjs/internal/indexRefCounter.js.map +1 -1
  45. package/dist/cjs/internal/parser.js +60 -17
  46. package/dist/cjs/internal/parser.js.map +1 -1
  47. package/dist/cjs/internal/parts.js +128 -28
  48. package/dist/cjs/internal/parts.js.map +1 -1
  49. package/dist/cjs/internal/render.js +486 -53
  50. package/dist/cjs/internal/render.js.map +1 -1
  51. package/dist/cjs/internal/server.js +5 -2
  52. package/dist/cjs/internal/server.js.map +1 -1
  53. package/dist/dts/Directive.d.ts.map +1 -1
  54. package/dist/dts/ElementRef.d.ts +4 -2
  55. package/dist/dts/ElementRef.d.ts.map +1 -1
  56. package/dist/dts/ElementSource.d.ts +10 -5
  57. package/dist/dts/ElementSource.d.ts.map +1 -1
  58. package/dist/dts/EventHandler.d.ts.map +1 -1
  59. package/dist/dts/Html.d.ts +1 -1
  60. package/dist/dts/Html.d.ts.map +1 -1
  61. package/dist/dts/HtmlChunk.d.ts.map +1 -1
  62. package/dist/dts/Many.d.ts +13 -11
  63. package/dist/dts/Many.d.ts.map +1 -1
  64. package/dist/dts/Parser.d.ts +3 -6
  65. package/dist/dts/Parser.d.ts.map +1 -1
  66. package/dist/dts/Part.d.ts +13 -3
  67. package/dist/dts/Part.d.ts.map +1 -1
  68. package/dist/dts/Placeholder.d.ts +2 -2
  69. package/dist/dts/Placeholder.d.ts.map +1 -1
  70. package/dist/dts/Render.d.ts +2 -1
  71. package/dist/dts/Render.d.ts.map +1 -1
  72. package/dist/dts/RenderContext.d.ts +5 -4
  73. package/dist/dts/RenderContext.d.ts.map +1 -1
  74. package/dist/dts/RenderTemplate.d.ts +2 -16
  75. package/dist/dts/RenderTemplate.d.ts.map +1 -1
  76. package/dist/dts/Renderable.d.ts +2 -2
  77. package/dist/dts/Renderable.d.ts.map +1 -1
  78. package/dist/dts/Template.d.ts +21 -3
  79. package/dist/dts/Template.d.ts.map +1 -1
  80. package/dist/dts/TemplateInstance.d.ts +3 -2
  81. package/dist/dts/TemplateInstance.d.ts.map +1 -1
  82. package/dist/dts/Test.d.ts +4 -6
  83. package/dist/dts/Test.d.ts.map +1 -1
  84. package/dist/dts/index.d.ts +0 -4
  85. package/dist/dts/index.d.ts.map +1 -1
  86. package/dist/dts/internal/EventSource.d.ts +12 -0
  87. package/dist/dts/internal/EventSource.d.ts.map +1 -0
  88. package/dist/dts/internal/browser.d.ts.map +1 -1
  89. package/dist/dts/internal/hydrate.d.ts +5 -5
  90. package/dist/dts/internal/hydrate.d.ts.map +1 -1
  91. package/dist/dts/internal/indexRefCounter.d.ts +5 -0
  92. package/dist/dts/internal/indexRefCounter.d.ts.map +1 -1
  93. package/dist/dts/internal/module-augmentation.d.ts +0 -4
  94. package/dist/dts/internal/module-augmentation.d.ts.map +1 -1
  95. package/dist/dts/internal/parser.d.ts +8 -0
  96. package/dist/dts/internal/parser.d.ts.map +1 -1
  97. package/dist/dts/internal/parts.d.ts +66 -56
  98. package/dist/dts/internal/parts.d.ts.map +1 -1
  99. package/dist/dts/internal/render.d.ts +7 -7
  100. package/dist/dts/internal/render.d.ts.map +1 -1
  101. package/dist/dts/internal/server.d.ts.map +1 -1
  102. package/dist/esm/Directive.js +1 -1
  103. package/dist/esm/Directive.js.map +1 -1
  104. package/dist/esm/ElementRef.js +12 -7
  105. package/dist/esm/ElementRef.js.map +1 -1
  106. package/dist/esm/ElementSource.js +16 -13
  107. package/dist/esm/ElementSource.js.map +1 -1
  108. package/dist/esm/EventHandler.js +1 -1
  109. package/dist/esm/EventHandler.js.map +1 -1
  110. package/dist/esm/Html.js +29 -24
  111. package/dist/esm/Html.js.map +1 -1
  112. package/dist/esm/HtmlChunk.js +6 -1
  113. package/dist/esm/HtmlChunk.js.map +1 -1
  114. package/dist/esm/Hydrate.js +1 -1
  115. package/dist/esm/Hydrate.js.map +1 -1
  116. package/dist/esm/Many.js +14 -10
  117. package/dist/esm/Many.js.map +1 -1
  118. package/dist/esm/Parser.js +6 -335
  119. package/dist/esm/Parser.js.map +1 -1
  120. package/dist/esm/Placeholder.js +2 -2
  121. package/dist/esm/Placeholder.js.map +1 -1
  122. package/dist/esm/Platform.js +2 -2
  123. package/dist/esm/Platform.js.map +1 -1
  124. package/dist/esm/Render.js +1 -1
  125. package/dist/esm/Render.js.map +1 -1
  126. package/dist/esm/RenderContext.js +38 -17
  127. package/dist/esm/RenderContext.js.map +1 -1
  128. package/dist/esm/RenderTemplate.js +2 -12
  129. package/dist/esm/RenderTemplate.js.map +1 -1
  130. package/dist/esm/Template.js +24 -0
  131. package/dist/esm/Template.js.map +1 -1
  132. package/dist/esm/TemplateInstance.js +2 -2
  133. package/dist/esm/TemplateInstance.js.map +1 -1
  134. package/dist/esm/Test.js +20 -7
  135. package/dist/esm/Test.js.map +1 -1
  136. package/dist/esm/index.js +0 -4
  137. package/dist/esm/index.js.map +1 -1
  138. package/dist/esm/internal/EventSource.js +91 -0
  139. package/dist/esm/internal/EventSource.js.map +1 -0
  140. package/dist/esm/internal/browser.js +12 -12
  141. package/dist/esm/internal/browser.js.map +1 -1
  142. package/dist/esm/internal/hydrate.js +45 -46
  143. package/dist/esm/internal/hydrate.js.map +1 -1
  144. package/dist/esm/internal/indexRefCounter.js +50 -2
  145. package/dist/esm/internal/indexRefCounter.js.map +1 -1
  146. package/dist/esm/internal/parser.js +84 -17
  147. package/dist/esm/internal/parser.js.map +1 -1
  148. package/dist/esm/internal/parts.js +110 -27
  149. package/dist/esm/internal/parts.js.map +1 -1
  150. package/dist/esm/internal/render.js +476 -58
  151. package/dist/esm/internal/render.js.map +1 -1
  152. package/dist/esm/internal/server.js +5 -4
  153. package/dist/esm/internal/server.js.map +1 -1
  154. package/package.json +10 -26
  155. package/src/Directive.ts +1 -1
  156. package/src/ElementRef.ts +18 -14
  157. package/src/ElementSource.ts +62 -47
  158. package/src/EventHandler.ts +1 -1
  159. package/src/Html.ts +58 -57
  160. package/src/HtmlChunk.ts +15 -1
  161. package/src/Hydrate.ts +1 -1
  162. package/src/Many.ts +53 -43
  163. package/src/Parser.ts +10 -453
  164. package/src/Part.ts +15 -3
  165. package/src/Placeholder.ts +4 -4
  166. package/src/Platform.ts +2 -2
  167. package/src/Render.ts +7 -2
  168. package/src/RenderContext.ts +47 -19
  169. package/src/RenderTemplate.ts +9 -54
  170. package/src/Renderable.ts +2 -1
  171. package/src/Template.ts +26 -0
  172. package/src/TemplateInstance.ts +9 -9
  173. package/src/Test.ts +40 -21
  174. package/src/index.ts +0 -4
  175. package/src/internal/EventSource.ts +153 -0
  176. package/src/internal/browser.ts +26 -25
  177. package/src/internal/hydrate.ts +68 -61
  178. package/src/internal/indexRefCounter.ts +63 -2
  179. package/src/internal/module-augmentation.ts +0 -4
  180. package/src/internal/parser.ts +92 -19
  181. package/src/internal/parts.ts +158 -73
  182. package/src/internal/render.ts +701 -89
  183. package/src/internal/server.ts +5 -3
  184. package/Token/package.json +0 -6
  185. package/Tokenizer/package.json +0 -6
  186. package/dist/cjs/Token.js +0 -270
  187. package/dist/cjs/Token.js.map +0 -1
  188. package/dist/cjs/Tokenizer.js +0 -18
  189. package/dist/cjs/Tokenizer.js.map +0 -1
  190. package/dist/cjs/internal/readAttribute.js +0 -34
  191. package/dist/cjs/internal/readAttribute.js.map +0 -1
  192. package/dist/cjs/internal/tokenizer.js +0 -264
  193. package/dist/cjs/internal/tokenizer.js.map +0 -1
  194. package/dist/dts/Token.d.ts +0 -202
  195. package/dist/dts/Token.d.ts.map +0 -1
  196. package/dist/dts/Tokenizer.d.ts +0 -6
  197. package/dist/dts/Tokenizer.d.ts.map +0 -1
  198. package/dist/dts/internal/readAttribute.d.ts +0 -9
  199. package/dist/dts/internal/readAttribute.d.ts.map +0 -1
  200. package/dist/dts/internal/tokenizer.d.ts +0 -3
  201. package/dist/dts/internal/tokenizer.d.ts.map +0 -1
  202. package/dist/esm/Token.js +0 -264
  203. package/dist/esm/Token.js.map +0 -1
  204. package/dist/esm/Tokenizer.js +0 -9
  205. package/dist/esm/Tokenizer.js.map +0 -1
  206. package/dist/esm/internal/readAttribute.js +0 -24
  207. package/dist/esm/internal/readAttribute.js.map +0 -1
  208. package/dist/esm/internal/tokenizer.js +0 -296
  209. package/dist/esm/internal/tokenizer.js.map +0 -1
  210. package/src/Token.ts +0 -269
  211. package/src/Tokenizer.ts +0 -10
  212. package/src/internal/readAttribute.ts +0 -28
  213. package/src/internal/tokenizer.ts +0 -338
@@ -1,21 +1,20 @@
1
1
  import * as Fx from "@typed/fx/Fx"
2
- import * as Subject from "@typed/fx/Subject"
3
- import type { Rendered } from "@typed/wire"
4
2
  import type { Cause } from "effect"
5
- import { Effect } from "effect"
6
- import * as ElementRef from "../ElementRef.js"
3
+ import * as Effect from "effect/Effect"
7
4
  import type { Placeholder } from "../Placeholder.js"
8
5
  import type { Renderable } from "../Renderable.js"
9
6
  import type { RenderContext } from "../RenderContext.js"
7
+ import type { RenderEvent } from "../RenderEvent.js"
10
8
  import { DomRenderEvent } from "../RenderEvent.js"
11
9
  import type { RenderTemplate } from "../RenderTemplate.js"
12
- import { TemplateInstance } from "../TemplateInstance.js"
13
10
  import { indexRefCounter } from "./indexRefCounter.js"
14
11
 
15
12
  import { unsafeGet } from "@typed/context"
16
13
 
14
+ import { Scope } from "effect/Scope"
17
15
  import type { Template } from "../Template.js"
18
16
  import { CouldNotFindCommentError, CouldNotFindRootElement } from "./errors.js"
17
+ import { type EventSource, makeEventSource } from "./EventSource.js"
19
18
  import { HydrateContext } from "./HydrateContext.js"
20
19
  import { buildParts, getBrowserEntry, renderTemplate, renderValues } from "./render.js"
21
20
  import {
@@ -33,61 +32,69 @@ import {
33
32
  * Here for "standard" browser rendering, a TemplateInstance is effectively a live
34
33
  * view into the contents rendered by the Template.
35
34
  */
36
- export const hydrateTemplate: (document: Document, ctx: RenderContext) => RenderTemplate =
37
- (document, renderContext) =>
38
- <Values extends ReadonlyArray<Renderable<any, any>>, T extends Rendered = Rendered>(
39
- templateStrings: TemplateStringsArray,
40
- values: Values,
41
- providedRef?: ElementRef.ElementRef<T>
42
- ) => {
43
- return Effect.gen(function*(_) {
44
- const context = yield* _(Effect.context<never>())
45
- const hydrateCtx = unsafeGet(context, HydrateContext)
46
-
47
- // If we're not longer hydrating, just render normally
48
- if (!hydrateCtx.hydrate) {
49
- return yield* _(renderTemplate(document, renderContext)(templateStrings, values, providedRef))
50
- }
35
+ export const hydrateTemplate: (document: Document, ctx: RenderContext) => RenderTemplate = (
36
+ document,
37
+ renderContext
38
+ ) => {
39
+ const render_ = renderTemplate(document, renderContext)
51
40
 
52
- const elementRef = providedRef || (yield* _(ElementRef.make<T>()))
53
- const events = Fx.map(elementRef, DomRenderEvent)
54
- const errors = Subject.make<Placeholder.Error<Values[number]>, never>()
55
-
56
- const { getParts, template, where, wire } = getHydrateEntry({
57
- ...hydrateCtx,
58
- document,
59
- renderContext,
60
- elementRef,
61
- strings: templateStrings,
62
- onCause: errors.onFailure
41
+ return <Values extends ReadonlyArray<Renderable<any, any>>>(
42
+ templateStrings: TemplateStringsArray,
43
+ values: Values
44
+ ): Fx.Fx<
45
+ Scope | Placeholder.Context<Values[number]>,
46
+ Placeholder.Error<Values[number]>,
47
+ RenderEvent
48
+ > => {
49
+ return Fx.make((sink) =>
50
+ Effect.gen(function*(_) {
51
+ const eventSource = makeEventSource()
52
+ const context = yield* _(Effect.context<Scope>())
53
+ const hydrateCtx = unsafeGet(context, HydrateContext)
54
+ const scope = unsafeGet(context, Scope)
55
+
56
+ // If we're not longer hydrating, just render normally
57
+ if (hydrateCtx.hydrate === false) {
58
+ return render_(templateStrings, values)
59
+ }
60
+
61
+ const { parts, template, where, wire } = getHydrateEntry({
62
+ ...hydrateCtx,
63
+ document,
64
+ renderContext,
65
+ eventSource,
66
+ strings: templateStrings,
67
+ onCause: sink.onFailure
68
+ })
69
+
70
+ // If there are parts we need to render them before constructing our Wire
71
+ if (parts.length > 0) {
72
+ const refCounter = yield* _(indexRefCounter(parts.length))
73
+
74
+ // Do the work
75
+ yield* _(
76
+ renderValues(values, parts, refCounter, context, (index: number): HydrateContext => ({
77
+ where,
78
+ rootIndex: index,
79
+ parentTemplate: template,
80
+ hydrate: true
81
+ }))
82
+ )
83
+
84
+ // Wait for initial work to be completed
85
+ yield* _(refCounter.wait)
86
+ }
87
+
88
+ hydrateCtx.hydrate = false
89
+
90
+ yield* _(eventSource.setup(wire, scope))
91
+
92
+ yield* _(sink.onSuccess(DomRenderEvent(wire)))
93
+ yield* _(Effect.never)
63
94
  })
64
- const parts = yield* _(getParts)
65
-
66
- // If there are parts we need to render them before constructing our Wire
67
- if (parts.length > 0) {
68
- const refCounter = yield* _(indexRefCounter(parts.length))
69
-
70
- // Do the work
71
- yield* _(renderValues(values, parts, refCounter, errors.onFailure, (index: number): HydrateContext => ({
72
- where,
73
- rootIndex: index,
74
- parentTemplate: template,
75
- hydrate: true
76
- })))
77
-
78
- // Wait for initial work to be completed
79
- yield* _(refCounter.wait)
80
- }
81
-
82
- hydrateCtx.hydrate = false
83
-
84
- // Set the element when it is ready
85
- yield* _(ElementRef.set(elementRef, wire as T))
86
-
87
- // Return the Template instance
88
- return TemplateInstance(Fx.merge([events, errors]), elementRef)
89
- })
95
+ )
90
96
  }
97
+ }
91
98
 
92
99
  export function findRootParentChildNodes(where: HTMLElement): ParentChildNodes {
93
100
  const childNodes = findRootChildNodes(where)
@@ -205,7 +212,7 @@ export function findPartComment(childNodes: ArrayLike<Node>, partIndex: number)
205
212
  export function getHydrateEntry({
206
213
  childIndex,
207
214
  document,
208
- elementRef,
215
+ eventSource,
209
216
  onCause,
210
217
  parentTemplate,
211
218
  renderContext,
@@ -219,7 +226,7 @@ export function getHydrateEntry({
219
226
  rootIndex: number
220
227
  parentTemplate: Template | null
221
228
  strings: TemplateStringsArray
222
- elementRef: ElementRef.ElementRef<any>
229
+ eventSource: EventSource
223
230
  onCause: (cause: Cause.Cause<any>) => Effect.Effect<never, never, void>
224
231
  childIndex?: number
225
232
  }) {
@@ -229,7 +236,7 @@ export function getHydrateEntry({
229
236
  where = findTemplateResultPartChildNodes(where, parentTemplate, template, rootIndex, childIndex)
230
237
  }
231
238
 
232
- const getParts = buildParts(document, renderContext, template, where, elementRef, onCause, true)
239
+ const parts = buildParts(document, renderContext, template, where, eventSource, onCause, true)
233
240
 
234
241
  const wire = (() => {
235
242
  if (!parentTemplate) {
@@ -256,7 +263,7 @@ export function getHydrateEntry({
256
263
  return {
257
264
  template,
258
265
  wire,
259
- getParts,
266
+ parts,
260
267
  where
261
268
  } as const
262
269
  }
@@ -1,5 +1,6 @@
1
1
  import * as Deferred from "effect/Deferred"
2
2
  import * as Effect from "effect/Effect"
3
+ import * as Option from "effect/Option"
3
4
 
4
5
  export type IndexRefCounter = {
5
6
  release: (index: number) => Effect.Effect<never, never, void>
@@ -15,13 +16,16 @@ export function indexRefCounter(expected: number): Effect.Effect<
15
16
  IndexRefCounter
16
17
  > {
17
18
  return Effect.map(Deferred.make<never, void>(), (deferred) => {
19
+ const done = Deferred.succeed(deferred, undefined)
18
20
  const indexes = new Set<number>(Array.from({ length: expected }, (_, i) => i))
19
21
 
20
22
  function release(index: number) {
21
23
  return Effect.suspend(() => {
22
24
  if (indexes.delete(index) && indexes.size === 0) {
23
- return Deferred.succeed(deferred, undefined)
24
- } else return Effect.unit
25
+ return done
26
+ } else {
27
+ return Effect.unit
28
+ }
25
29
  })
26
30
  }
27
31
 
@@ -31,3 +35,60 @@ export function indexRefCounter(expected: number): Effect.Effect<
31
35
  }
32
36
  })
33
37
  }
38
+
39
+ export type IndexRefCounter2 = {
40
+ release: (index: number) => Effect.Effect<never, never, void>
41
+ expect: (count: number) => Effect.Effect<never, never, boolean>
42
+ wait: Effect.Effect<never, never, void>
43
+ }
44
+
45
+ /**
46
+ * @internal
47
+ */
48
+ export function indexRefCounter2(): Effect.Effect<
49
+ never,
50
+ never,
51
+ IndexRefCounter2
52
+ > {
53
+ return Effect.map(Deferred.make<never, void>(), (deferred) => {
54
+ let expected: Option.Option<number> = Option.none<number>()
55
+ const done = Deferred.succeed(deferred, undefined)
56
+ const indexes = new Set<number>()
57
+
58
+ function isDone() {
59
+ if (Option.isSome(expected)) {
60
+ return indexes.size === expected.value
61
+ } else {
62
+ return false
63
+ }
64
+ }
65
+
66
+ function release(index: number) {
67
+ return Effect.suspend(() => {
68
+ indexes.add(index)
69
+ if (isDone()) {
70
+ return done
71
+ } else {
72
+ return Effect.succeed(false)
73
+ }
74
+ })
75
+ }
76
+
77
+ function expect(count: number) {
78
+ return Effect.suspend(() => {
79
+ expected = Option.some(count)
80
+ if (isDone()) {
81
+ return Effect.as(done, false)
82
+ } else {
83
+ return Effect.succeed(true)
84
+ }
85
+ })
86
+ }
87
+
88
+ return {
89
+ release,
90
+ expect,
91
+ wait: Deferred.await(deferred)
92
+ }
93
+ })
94
+ }
@@ -42,7 +42,3 @@ declare global {
42
42
  declare module "@typed/fx/Fx" {
43
43
  export interface Fx<R, E, A> extends Placeholder<R, E, A> {}
44
44
  }
45
-
46
- declare module "effect/Effect" {
47
- export interface Effect<R, E, A> extends Placeholder<R, E, A> {}
48
- }
@@ -2,7 +2,6 @@ import * as Chunk from "effect/Chunk"
2
2
  import { globalValue } from "effect/GlobalValue"
3
3
  import * as Option from "effect/Option"
4
4
  import * as Template from "../Template.js"
5
- import { SELF_CLOSING_TAGS, TEXT_ONLY_NODES_REGEX } from "../Token.js"
6
5
  import type { TextChunk } from "./chunks.js"
7
6
  import {
8
7
  getPart,
@@ -16,6 +15,40 @@ import {
16
15
  // TODO: Consider ways to surface useful errors and warnings.
17
16
  // TODO: Profile for performance optimization
18
17
 
18
+ /**
19
+ * @since 1.0.0
20
+ */
21
+ export const TEXT_ONLY_NODES_REGEX = new Set([
22
+ "textarea",
23
+ "script",
24
+ "style",
25
+ "title",
26
+ "plaintext",
27
+ "xmp"
28
+ ])
29
+
30
+ /**
31
+ * @since 1.0.0
32
+ */
33
+ export const SELF_CLOSING_TAGS = new Set([
34
+ "area",
35
+ "base",
36
+ "br",
37
+ "col",
38
+ "command",
39
+ "embed",
40
+ "hr",
41
+ "img",
42
+ "input",
43
+ "keygen",
44
+ "link",
45
+ "meta",
46
+ "param",
47
+ "source",
48
+ "track",
49
+ "wbr"
50
+ ])
51
+
19
52
  export interface Parser {
20
53
  parse(templateStrings: ReadonlyArray<string>): Template.Template
21
54
  }
@@ -25,18 +58,38 @@ export function parse(templateStrings: ReadonlyArray<string>): Template.Template
25
58
  }
26
59
 
27
60
  const SPACE_REGEX = /\s/
28
- const isPartToken: TextPredicate = (input, pos) => input[pos] === "{" && input.slice(pos, pos + 8) === "{{__PART"
29
- const isPartEndToken: TextPredicate = (input, pos) => input[pos] === "_" && input.slice(pos, pos + 4) === "__}}"
30
- const isElementOpenToken: TextPredicate = (input, pos) => input[pos] === "<" && input[pos + 1] !== "/"
31
- const isElementCloseToken: TextPredicate = (input, pos) => input[pos] === "<" && input[pos + 1] === "/"
32
- const isEqualsToken: TextPredicate = (input, pos) => input[pos] === "="
33
- const isQuoteToken: TextPredicate = (input, pos) => input[pos] === `"`
34
- const isSingleQuoteToken: TextPredicate = (input, pos) => input[pos] === "'"
61
+ const PART_START = "{{__PART"
62
+ const PART_END = "__}}"
63
+ const chars = {
64
+ openBracket: "{",
65
+ closeBracket: "}",
66
+ underscore: "_",
67
+ equals: "=",
68
+ quote: `"`,
69
+ singleQuote: "'",
70
+ slash: "/",
71
+ greaterThan: ">",
72
+ lessThan: "<",
73
+ hypen: "-"
74
+ } as const
75
+
76
+ const isPartToken: TextPredicate = (input, pos) =>
77
+ input[pos] === chars.openBracket && input.slice(pos, pos + 8) === PART_START
78
+ const isPartEndToken: TextPredicate = (input, pos) =>
79
+ input[pos] === chars.underscore && input.slice(pos, pos + 4) === PART_END
80
+ const isElementOpenToken: TextPredicate = (input, pos) =>
81
+ input[pos] === chars.lessThan && input[pos + 1] !== chars.slash
82
+ const isElementCloseToken: TextPredicate = (input, pos) =>
83
+ input[pos] === chars.lessThan && input[pos + 1] === chars.slash
84
+ const isEqualsToken: TextPredicate = (input, pos) => input[pos] === chars.equals
85
+ const isQuoteToken: TextPredicate = (input, pos) => input[pos] === chars.quote
86
+ const isSingleQuoteToken: TextPredicate = (input, pos) => input[pos] === chars.singleQuote
35
87
  const isWhitespaceToken: TextPredicate = (input, pos) => SPACE_REGEX.test(input[pos])
36
- const isOpenTagEndToken: TextPredicate = (input, pos) => input[pos] === ">"
37
- const isSelfClosingTagEndToken: TextPredicate = (input, pos) => input[pos] === "/" && input[pos + 1] === ">"
88
+ const isOpenTagEndToken: TextPredicate = (input, pos) => input[pos] === chars.greaterThan
89
+ const isSelfClosingTagEndToken: TextPredicate = (input, pos) =>
90
+ input[pos] === chars.slash && input[pos + 1] === chars.greaterThan
38
91
  const isCommentEndToken: TextPredicate = (input, pos) =>
39
- input[pos] === "-" && input[pos + 1] === "-" && input[pos + 2] === ">"
92
+ input[pos] === chars.hypen && input[pos + 1] === chars.hypen && input[pos + 2] === chars.greaterThan
40
93
 
41
94
  type Context = "unknown" | "element"
42
95
 
@@ -154,6 +207,7 @@ class ParserImpl implements Parser {
154
207
 
155
208
  while (this.pos < this.length) {
156
209
  const node = this.parseNodeFromContext(this.context)
210
+
157
211
  if (node === undefined) {
158
212
  return nodes
159
213
  } else {
@@ -187,9 +241,16 @@ class ParserImpl implements Parser {
187
241
  const nextChar = this.nextChar()
188
242
 
189
243
  if (nextChar === "!") { // Comment
190
- this.consumeAmount(3)
244
+ this.consumeAmount(1)
245
+
246
+ const nextChar = this.nextChar()
191
247
 
192
- return [this.parseComment()]
248
+ if (nextChar == "-") {
249
+ this.consumeAmount(2)
250
+ return [this.parseComment()]
251
+ } else {
252
+ return [this.parseDocType()]
253
+ }
193
254
  } else if (nextChar === "/") { // Self-closing tag
194
255
  return this.selfClosingTagEnd()
195
256
  } else { // Elements
@@ -263,6 +324,7 @@ class ParserImpl implements Parser {
263
324
 
264
325
  private parseTextOnlyElement(tagName: string): Template.TextOnlyElement {
265
326
  const attributes = this.parseAttributes()
327
+
266
328
  this.path.push()
267
329
  const children = this.parseTextChildren()
268
330
  this.path.pop()
@@ -289,6 +351,14 @@ class ParserImpl implements Parser {
289
351
  return this.addPart(new Template.SparseCommentNode(textAndParts))
290
352
  }
291
353
 
354
+ private parseDocType(): Template.DocType {
355
+ this.parseTextUntil((char) => char === chars.greaterThan)
356
+ this.consumeAmount(1)
357
+ this.skipWhitespace()
358
+
359
+ return new Template.DocType("html")
360
+ }
361
+
292
362
  private parseTagName() {
293
363
  return this.parseTextUntilMany(tagNameMatches)
294
364
  }
@@ -304,6 +374,7 @@ class ParserImpl implements Parser {
304
374
  case null:
305
375
  return Skip
306
376
  case "whitespace":
377
+ this.skipWhitespace()
307
378
  return Continue([new Template.BooleanNode(name)])
308
379
  case "equals": {
309
380
  this.consumeAmount(1)
@@ -366,11 +437,13 @@ class ParserImpl implements Parser {
366
437
  case ".": {
367
438
  const property = name.slice(1)
368
439
 
369
- return this.addPart(
370
- property === "data"
371
- ? new Template.DataPartNode(unsafeParsePartIndex(text))
372
- : new Template.PropertyPartNode(property, unsafeParsePartIndex(text))
373
- )
440
+ if (property === "data") {
441
+ return this.addPart(new Template.DataPartNode(unsafeParsePartIndex(text)))
442
+ } else if (property === "props" || property === "properties") {
443
+ return this.addPart(new Template.PropertiesPartNode(unsafeParsePartIndex(text)))
444
+ } else {
445
+ return this.addPart(new Template.PropertyPartNode(property, unsafeParsePartIndex(text)))
446
+ }
374
447
  }
375
448
  case "@":
376
449
  return this.addPart(new Template.EventPartNode(name.slice(1), unsafeParsePartIndex(text)))
@@ -617,7 +690,7 @@ function parseTextAndParts<T>(s: string, f: (index: number) => T): Array<Templat
617
690
  return out
618
691
  }
619
692
 
620
- export const parser: Parser = globalValue(Symbol.for("../Parser2.js"), () => new ParserImpl())
693
+ export const parser: Parser = globalValue(Symbol.for("@typed/template/Parser2"), () => new ParserImpl())
621
694
 
622
695
  const digestSize = 2
623
696
  const multiplier = 33