@typed/template 0.9.4 → 0.9.5
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/dist/cjs/Directive.js.map +1 -1
- package/dist/cjs/ElementRef.js.map +1 -1
- package/dist/cjs/ElementSource.js.map +1 -1
- package/dist/cjs/Entry.js.map +1 -1
- package/dist/cjs/EventHandler.js.map +1 -1
- package/dist/cjs/Html.js +9 -6
- package/dist/cjs/Html.js.map +1 -1
- package/dist/cjs/HtmlChunk.js.map +1 -1
- package/dist/cjs/Hydrate.js.map +1 -1
- package/dist/cjs/Many.js +21 -21
- package/dist/cjs/Many.js.map +1 -1
- package/dist/cjs/Meta.js.map +1 -1
- package/dist/cjs/Parser.js.map +1 -1
- package/dist/cjs/Part.js.map +1 -1
- package/dist/cjs/Placeholder.js.map +1 -1
- package/dist/cjs/Platform.js.map +1 -1
- package/dist/cjs/Render.js.map +1 -1
- package/dist/cjs/RenderContext.js.map +1 -1
- package/dist/cjs/RenderEvent.js.map +1 -1
- package/dist/cjs/RenderTemplate.js.map +1 -1
- package/dist/cjs/Renderable.js.map +1 -1
- package/dist/cjs/Template.js +2 -1
- package/dist/cjs/Template.js.map +1 -1
- package/dist/cjs/Test.js +3 -11
- package/dist/cjs/Test.js.map +1 -1
- package/dist/cjs/Vitest.js +16 -0
- package/dist/cjs/Vitest.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/EventSource.js.map +1 -1
- package/dist/cjs/internal/HydrateContext.js.map +1 -1
- package/dist/cjs/internal/browser.js.map +1 -1
- package/dist/cjs/internal/chunks.js.map +1 -1
- package/dist/cjs/internal/errors.js.map +1 -1
- package/dist/cjs/internal/hydrate.js +1 -1
- package/dist/cjs/internal/hydrate.js.map +1 -1
- package/dist/cjs/internal/indexRefCounter.js.map +1 -1
- package/dist/cjs/internal/module-augmentation.js.map +1 -1
- package/dist/cjs/internal/parser.js +10 -5
- package/dist/cjs/internal/parser.js.map +1 -1
- package/dist/cjs/internal/parts.js +2 -1
- package/dist/cjs/internal/parts.js.map +1 -1
- package/dist/cjs/internal/render.js +38 -17
- package/dist/cjs/internal/render.js.map +1 -1
- package/dist/cjs/internal/server.js.map +1 -1
- package/dist/cjs/internal/utils.js.map +1 -1
- package/dist/dts/Html.d.ts +7 -0
- package/dist/dts/Html.d.ts.map +1 -1
- package/dist/dts/Template.d.ts.map +1 -1
- package/dist/dts/Test.d.ts +3 -0
- package/dist/dts/Test.d.ts.map +1 -1
- package/dist/dts/Vitest.d.ts +12 -0
- package/dist/dts/Vitest.d.ts.map +1 -1
- package/dist/dts/internal/parser.d.ts.map +1 -1
- package/dist/dts/internal/parts.d.ts.map +1 -1
- package/dist/dts/internal/render.d.ts.map +1 -1
- package/dist/esm/Html.js +9 -7
- package/dist/esm/Html.js.map +1 -1
- package/dist/esm/Many.js +18 -18
- package/dist/esm/Many.js.map +1 -1
- package/dist/esm/Template.js +2 -1
- package/dist/esm/Template.js.map +1 -1
- package/dist/esm/Test.js +4 -12
- package/dist/esm/Test.js.map +1 -1
- package/dist/esm/Vitest.js +12 -0
- package/dist/esm/Vitest.js.map +1 -1
- package/dist/esm/internal/hydrate.js +1 -1
- package/dist/esm/internal/hydrate.js.map +1 -1
- package/dist/esm/internal/parser.js +10 -6
- package/dist/esm/internal/parser.js.map +1 -1
- package/dist/esm/internal/parts.js +2 -3
- package/dist/esm/internal/parts.js.map +1 -1
- package/dist/esm/internal/render.js +37 -17
- package/dist/esm/internal/render.js.map +1 -1
- package/package.json +9 -9
- package/src/Html.ts +10 -16
- package/src/Many.ts +26 -26
- package/src/Template.ts +2 -1
- package/src/Test.ts +15 -18
- package/src/Vitest.ts +70 -0
- package/src/internal/hydrate.ts +1 -1
- package/src/internal/parser.ts +12 -6
- package/src/internal/parts.ts +2 -3
- package/src/internal/render.ts +53 -23
package/src/Vitest.ts
CHANGED
|
@@ -38,6 +38,38 @@ export function it<E, A>(
|
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
it.only = function it<E, A>(
|
|
42
|
+
name: string,
|
|
43
|
+
test: () => Effect.Effect<A, E, Scope>,
|
|
44
|
+
options?: vitest.TestOptions
|
|
45
|
+
) {
|
|
46
|
+
return vitest.it.only(
|
|
47
|
+
name,
|
|
48
|
+
() =>
|
|
49
|
+
test().pipe(
|
|
50
|
+
Effect.scoped,
|
|
51
|
+
Effect.runPromise
|
|
52
|
+
),
|
|
53
|
+
options
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
it.skip = function it<E, A>(
|
|
58
|
+
name: string,
|
|
59
|
+
test: () => Effect.Effect<A, E, Scope>,
|
|
60
|
+
options?: vitest.TestOptions
|
|
61
|
+
) {
|
|
62
|
+
return vitest.it.skip(
|
|
63
|
+
name,
|
|
64
|
+
() =>
|
|
65
|
+
test().pipe(
|
|
66
|
+
Effect.scoped,
|
|
67
|
+
Effect.runPromise
|
|
68
|
+
),
|
|
69
|
+
options
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
41
73
|
/**
|
|
42
74
|
* @since 1.0.0
|
|
43
75
|
*/
|
|
@@ -59,3 +91,41 @@ export function test<E, A>(
|
|
|
59
91
|
options
|
|
60
92
|
)
|
|
61
93
|
}
|
|
94
|
+
|
|
95
|
+
test.only = function test<E, A>(
|
|
96
|
+
name: string,
|
|
97
|
+
test: (options: {
|
|
98
|
+
readonly clock: TestClock.TestClock
|
|
99
|
+
}) => Effect.Effect<A, E, Scope | TestServices.TestServices>,
|
|
100
|
+
options?: vitest.TestOptions
|
|
101
|
+
) {
|
|
102
|
+
return vitest.it.only(
|
|
103
|
+
name,
|
|
104
|
+
() =>
|
|
105
|
+
TestClock.testClockWith((clock) => test({ clock })).pipe(
|
|
106
|
+
Effect.provide(TestContext.TestContext),
|
|
107
|
+
Effect.scoped,
|
|
108
|
+
Effect.runPromise
|
|
109
|
+
),
|
|
110
|
+
options
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
test.skip = function test<E, A>(
|
|
115
|
+
name: string,
|
|
116
|
+
test: (options: {
|
|
117
|
+
readonly clock: TestClock.TestClock
|
|
118
|
+
}) => Effect.Effect<A, E, Scope | TestServices.TestServices>,
|
|
119
|
+
options?: vitest.TestOptions
|
|
120
|
+
) {
|
|
121
|
+
return vitest.it.skip(
|
|
122
|
+
name,
|
|
123
|
+
() =>
|
|
124
|
+
TestClock.testClockWith((clock) => test({ clock })).pipe(
|
|
125
|
+
Effect.provide(TestContext.TestContext),
|
|
126
|
+
Effect.scoped,
|
|
127
|
+
Effect.runPromise
|
|
128
|
+
),
|
|
129
|
+
options
|
|
130
|
+
)
|
|
131
|
+
}
|
package/src/internal/hydrate.ts
CHANGED
|
@@ -161,7 +161,7 @@ export function findRootChildNodes(where: HTMLElement): Array<Node> {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
for (let i = length - 1; i >= start; i--) {
|
|
164
|
+
for (let i = length - 1; i >= Math.max(start, 0); i--) {
|
|
165
165
|
const node = childNodes[i]
|
|
166
166
|
|
|
167
167
|
if (node.nodeType === node.COMMENT_NODE && node.nodeValue === END) {
|
package/src/internal/parser.ts
CHANGED
|
@@ -287,10 +287,11 @@ class ParserImpl implements Parser {
|
|
|
287
287
|
this._skipWhitespace = false
|
|
288
288
|
return [this.addPartWithPrevious(new Template.NodePart(parseInt(next.match[2], 10)))]
|
|
289
289
|
} else if ((next = this.chunk(getWhitespace))) { // Whitespace
|
|
290
|
-
return this._skipWhitespace ? [] : [new Template.TextNode(next.match[1])]
|
|
290
|
+
return this._skipWhitespace ? [] : (this.path.inc(), [new Template.TextNode(next.match[1])])
|
|
291
291
|
} else if ((next = this.chunk(getTextUntilCloseBrace))) { // Text and parts
|
|
292
292
|
return parseTextAndParts(next.match[1], (i) => this.addPartWithPrevious(new Template.NodePart(i)))
|
|
293
293
|
} else {
|
|
294
|
+
this.path.inc()
|
|
294
295
|
return [new Template.TextNode(this.nextChar())]
|
|
295
296
|
}
|
|
296
297
|
}
|
|
@@ -346,7 +347,7 @@ class ParserImpl implements Parser {
|
|
|
346
347
|
const attributes = this.parseAttributes()
|
|
347
348
|
|
|
348
349
|
this.path.push()
|
|
349
|
-
const children = this.parseTextChildren()
|
|
350
|
+
const children = this.parseTextChildren(tagName)
|
|
350
351
|
this.path.pop()
|
|
351
352
|
|
|
352
353
|
return new Template.TextOnlyElement(tagName, attributes, children || [])
|
|
@@ -516,11 +517,11 @@ class ParserImpl implements Parser {
|
|
|
516
517
|
}
|
|
517
518
|
}
|
|
518
519
|
|
|
519
|
-
private parseTextChildren(): Array<Template.Text> | null {
|
|
520
|
-
return this.parseArray(() => this.parseTextChild())
|
|
520
|
+
private parseTextChildren(tagName: string): Array<Template.Text> | null {
|
|
521
|
+
return this.parseArray(() => this.parseTextChild(tagName))
|
|
521
522
|
}
|
|
522
523
|
|
|
523
|
-
private parseTextChild(): LoopDecision<Array<Template.Text>> {
|
|
524
|
+
private parseTextChild(tagName: string): LoopDecision<Array<Template.Text>> {
|
|
524
525
|
const [parsed, matched] = this.parseTextUntilMany(textChildMatches)
|
|
525
526
|
const text = parsed.trim()
|
|
526
527
|
|
|
@@ -533,7 +534,12 @@ class ParserImpl implements Parser {
|
|
|
533
534
|
|
|
534
535
|
return text === "" ? Continue([part]) : Continue([new Template.TextNode(text), part])
|
|
535
536
|
}
|
|
536
|
-
case "elementClose":
|
|
537
|
+
case "elementClose": {
|
|
538
|
+
this.consumeClosingTag(tagName)
|
|
539
|
+
return Break(
|
|
540
|
+
text ? [new Template.TextNode(text)] : undefined
|
|
541
|
+
)
|
|
542
|
+
}
|
|
537
543
|
case "elementOpen": // In this case we make the assumption that you forgot to close this element
|
|
538
544
|
return Break(
|
|
539
545
|
text ? [new Template.TextNode(text)] : undefined
|
package/src/internal/parts.ts
CHANGED
|
@@ -334,9 +334,8 @@ export class TextPartImpl extends base("text") implements TextPart {
|
|
|
334
334
|
// TODO: Make this properly
|
|
335
335
|
static browser(document: Document, index: number, element: Element, ctx: RenderContext) {
|
|
336
336
|
const comment = findHoleComment(element, index)
|
|
337
|
-
const text =
|
|
338
|
-
|
|
339
|
-
: document.createTextNode("")
|
|
337
|
+
const text = document.createTextNode("")
|
|
338
|
+
element.insertBefore(text, comment)
|
|
340
339
|
|
|
341
340
|
return new TextPartImpl(
|
|
342
341
|
index,
|
package/src/internal/render.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Effect, ExecutionStrategy, Exit, Runtime } from "effect"
|
|
|
7
7
|
import type { Cause } from "effect/Cause"
|
|
8
8
|
import type { Chunk } from "effect/Chunk"
|
|
9
9
|
import * as Context from "effect/Context"
|
|
10
|
+
import { hasProperty } from "effect/Predicate"
|
|
10
11
|
import * as Scope from "effect/Scope"
|
|
11
12
|
import { uncapitalize } from "effect/String"
|
|
12
13
|
import type { Directive } from "../Directive.js"
|
|
@@ -41,7 +42,7 @@ import {
|
|
|
41
42
|
TextPartImpl
|
|
42
43
|
} from "./parts.js"
|
|
43
44
|
import type { ParentChildNodes } from "./utils.js"
|
|
44
|
-
import {
|
|
45
|
+
import { findPath } from "./utils.js"
|
|
45
46
|
|
|
46
47
|
// TODO: We need to re-think hydration for dynamic lists, probably just markers should be fine
|
|
47
48
|
|
|
@@ -77,7 +78,7 @@ const RenderPartMap: RenderPartMap = {
|
|
|
77
78
|
const element = node as HTMLElement | SVGElement
|
|
78
79
|
const attr = createAttribute(document, element, templatePart.name)
|
|
79
80
|
const renderable = values[templatePart.index]
|
|
80
|
-
let isSet =
|
|
81
|
+
let isSet = false
|
|
81
82
|
const setValue = (value: string | null | undefined) => {
|
|
82
83
|
if (isNullOrUndefined(value)) {
|
|
83
84
|
element.removeAttribute(templatePart.name)
|
|
@@ -147,10 +148,10 @@ const RenderPartMap: RenderPartMap = {
|
|
|
147
148
|
},
|
|
148
149
|
"comment-part": (templatePart, node, ctx) => {
|
|
149
150
|
const { refCounter, renderContext, values } = ctx
|
|
150
|
-
const comment =
|
|
151
|
+
const comment = node as Comment
|
|
151
152
|
const renderable = values[templatePart.index]
|
|
152
153
|
const setValue = (value: string | null | undefined) => {
|
|
153
|
-
comment.
|
|
154
|
+
comment.nodeValue = isNullOrUndefined(value) ? "" : String(value)
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
return matchSettablePart(
|
|
@@ -242,7 +243,7 @@ const RenderPartMap: RenderPartMap = {
|
|
|
242
243
|
"property": (templatePart, node, ctx) => {
|
|
243
244
|
const element = node as HTMLElement | SVGElement
|
|
244
245
|
const renderable = ctx.values[templatePart.index]
|
|
245
|
-
const setValue = (value:
|
|
246
|
+
const setValue = (value: unknown) => {
|
|
246
247
|
if (isNullOrUndefined(value)) {
|
|
247
248
|
delete (element as any)[templatePart.name]
|
|
248
249
|
} else {
|
|
@@ -260,7 +261,6 @@ const RenderPartMap: RenderPartMap = {
|
|
|
260
261
|
},
|
|
261
262
|
"properties": (templatePart, node, ctx) => {
|
|
262
263
|
const renderable = ctx.values[templatePart.index] as any as Record<string, any>
|
|
263
|
-
|
|
264
264
|
if (isNullOrUndefined(renderable)) return null
|
|
265
265
|
else if (Fx.isFx(renderable) || Effect.isEffect(renderable)) {
|
|
266
266
|
throw new Error(`Properties Part must utilize an Record of renderable values.`)
|
|
@@ -407,11 +407,9 @@ const RenderPartMap: RenderPartMap = {
|
|
|
407
407
|
const element = node as HTMLElement | SVGElement
|
|
408
408
|
const attr = createAttribute(ctx.document, element, templatePart.name)
|
|
409
409
|
|
|
410
|
-
const setValue = (value: string | null | undefined, index: number) =>
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
return ctx.renderContext.queue.add(element, () => attr.value = values.join(""))
|
|
414
|
-
})
|
|
410
|
+
const setValue = (value: string | null | undefined, index: number) => {
|
|
411
|
+
values[index] = value ?? ""
|
|
412
|
+
}
|
|
415
413
|
|
|
416
414
|
const effects: Array<Effect.Effect<void, any, any>> = []
|
|
417
415
|
|
|
@@ -429,7 +427,11 @@ const RenderPartMap: RenderPartMap = {
|
|
|
429
427
|
new AttributePartImpl(
|
|
430
428
|
templatePart.name,
|
|
431
429
|
node.index,
|
|
432
|
-
({ value }) =>
|
|
430
|
+
({ value }) =>
|
|
431
|
+
Effect.zipRight(
|
|
432
|
+
ctx.renderContext.queue.add(element, () => setValue(value, index)),
|
|
433
|
+
ctx.refCounter.release(node.index)
|
|
434
|
+
),
|
|
433
435
|
attr.value
|
|
434
436
|
),
|
|
435
437
|
(f) => Effect.zipRight(ctx.renderContext.queue.add(element, f), ctx.refCounter.release(node.index)),
|
|
@@ -442,6 +444,11 @@ const RenderPartMap: RenderPartMap = {
|
|
|
442
444
|
}
|
|
443
445
|
}
|
|
444
446
|
|
|
447
|
+
if (effects.length === 0) {
|
|
448
|
+
attr.value = values.join("")
|
|
449
|
+
element.setAttributeNode(attr)
|
|
450
|
+
}
|
|
451
|
+
|
|
445
452
|
return effects
|
|
446
453
|
},
|
|
447
454
|
"sparse-class-name": (templatePart, node, ctx) => {
|
|
@@ -465,11 +472,12 @@ const RenderPartMap: RenderPartMap = {
|
|
|
465
472
|
const values = Array.from({ length: templatePart.nodes.length }, (): string => "")
|
|
466
473
|
const comment = node as Comment
|
|
467
474
|
|
|
468
|
-
const setValue = (value: string | null | undefined, index: number) =>
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
475
|
+
const setValue = (value: string | null | undefined, index: number) => {
|
|
476
|
+
values[index] = value ?? ""
|
|
477
|
+
}
|
|
478
|
+
const flushValue = () => {
|
|
479
|
+
comment.data = values.join("")
|
|
480
|
+
}
|
|
473
481
|
|
|
474
482
|
const effects: Array<Effect.Effect<void, any, any>> = []
|
|
475
483
|
|
|
@@ -482,11 +490,18 @@ const RenderPartMap: RenderPartMap = {
|
|
|
482
490
|
const index = i
|
|
483
491
|
const effect = matchSettablePart(
|
|
484
492
|
renderable,
|
|
485
|
-
(value) =>
|
|
493
|
+
(value) => {
|
|
494
|
+
setValue(value, index)
|
|
495
|
+
flushValue()
|
|
496
|
+
},
|
|
486
497
|
() =>
|
|
487
498
|
new CommentPartImpl(
|
|
488
499
|
node.index,
|
|
489
|
-
({ value }) => setValue(value, index),
|
|
500
|
+
({ value }) => (setValue(value, index),
|
|
501
|
+
Effect.zipRight(
|
|
502
|
+
ctx.renderContext.queue.add(comment, () => flushValue()),
|
|
503
|
+
ctx.refCounter.release(node.index)
|
|
504
|
+
)),
|
|
490
505
|
null
|
|
491
506
|
),
|
|
492
507
|
(f) => Effect.zipRight(ctx.renderContext.queue.add(comment, f), ctx.refCounter.release(node.index)),
|
|
@@ -499,6 +514,10 @@ const RenderPartMap: RenderPartMap = {
|
|
|
499
514
|
}
|
|
500
515
|
}
|
|
501
516
|
|
|
517
|
+
if (effects.length === 0) {
|
|
518
|
+
flushValue()
|
|
519
|
+
}
|
|
520
|
+
|
|
502
521
|
return effects
|
|
503
522
|
},
|
|
504
523
|
"text-part": (templatePart, node, ctx) => {
|
|
@@ -750,8 +769,6 @@ function removeChildren(where: HTMLElement, previous: Rendered) {
|
|
|
750
769
|
}
|
|
751
770
|
|
|
752
771
|
function replaceChildren(where: HTMLElement, wire: Rendered) {
|
|
753
|
-
console.log("replaceChildren", wire)
|
|
754
|
-
|
|
755
772
|
where.replaceChildren(...getNodes(wire))
|
|
756
773
|
}
|
|
757
774
|
|
|
@@ -805,7 +822,7 @@ function buildNode(document: Document, node: Template.Node, isSvgContext: boolea
|
|
|
805
822
|
case "comment":
|
|
806
823
|
return document.createComment(node.value)
|
|
807
824
|
case "sparse-comment":
|
|
808
|
-
return document.createComment("")
|
|
825
|
+
return document.createComment(`hole${node.nodes.map((n) => n._tag === "text" ? "" : n.index).join("")}`)
|
|
809
826
|
// Create placeholders for these elements
|
|
810
827
|
case "comment-part":
|
|
811
828
|
case "node":
|
|
@@ -914,7 +931,7 @@ function matchSettablePart(
|
|
|
914
931
|
Directive: (directive) => {
|
|
915
932
|
expect()
|
|
916
933
|
const part = makePart()
|
|
917
|
-
return
|
|
934
|
+
return runDirective(directive, part, setValue, schedule)
|
|
918
935
|
},
|
|
919
936
|
Otherwise: (otherwise) => {
|
|
920
937
|
setValue(otherwise)
|
|
@@ -939,3 +956,16 @@ function matchRenderable(renderable: Renderable<any, any>, matches: {
|
|
|
939
956
|
return matches.Otherwise(renderable)
|
|
940
957
|
}
|
|
941
958
|
}
|
|
959
|
+
|
|
960
|
+
function runDirective(
|
|
961
|
+
directive: Directive<any, any>,
|
|
962
|
+
part: Part,
|
|
963
|
+
setValue: (value: any) => void,
|
|
964
|
+
schedule: (f: () => void) => Effect.Effect<void, never, Scope.Scope>
|
|
965
|
+
): Effect.Effect<void, any, any> {
|
|
966
|
+
if (hasProperty(part, "update")) {
|
|
967
|
+
return directive({ ...part, update: (value: any) => schedule(() => setValue(value)) })
|
|
968
|
+
} else {
|
|
969
|
+
return Effect.flatMap(directive(part), () => schedule(() => setValue(part.value)))
|
|
970
|
+
}
|
|
971
|
+
}
|