@microsoft/fast-html 1.0.0-alpha.1 → 1.0.0-alpha.11

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 (69) hide show
  1. package/README.md +100 -7
  2. package/dist/dts/components/index.d.ts +1 -0
  3. package/dist/dts/components/template.d.ts +74 -0
  4. package/dist/dts/components/utilities.d.ts +125 -0
  5. package/dist/dts/components/utilities.spec.d.ts +1 -0
  6. package/dist/dts/debug.d.ts +3 -0
  7. package/dist/dts/fixtures/attribute/attribute.spec.d.ts +1 -0
  8. package/dist/dts/fixtures/attribute/main.d.ts +1 -0
  9. package/dist/dts/fixtures/binding/binding.spec.d.ts +1 -0
  10. package/dist/dts/fixtures/binding/main.d.ts +1 -0
  11. package/dist/dts/fixtures/children/children.spec.d.ts +1 -0
  12. package/dist/dts/fixtures/children/main.d.ts +1 -0
  13. package/dist/dts/fixtures/dot-syntax/dot-syntax.spec.d.ts +1 -0
  14. package/dist/dts/fixtures/dot-syntax/main.d.ts +1 -0
  15. package/dist/dts/fixtures/event/event.spec.d.ts +1 -0
  16. package/dist/dts/fixtures/event/main.d.ts +1 -0
  17. package/dist/dts/fixtures/partial/main.d.ts +1 -0
  18. package/dist/dts/fixtures/partial/partial.spec.d.ts +1 -0
  19. package/dist/dts/fixtures/ref/main.d.ts +1 -0
  20. package/dist/dts/fixtures/ref/ref.spec.d.ts +1 -0
  21. package/dist/dts/fixtures/repeat/main.d.ts +1 -0
  22. package/dist/dts/fixtures/repeat/repeat.spec.d.ts +1 -0
  23. package/dist/dts/fixtures/slotted/main.d.ts +1 -0
  24. package/dist/dts/fixtures/slotted/slotted.spec.d.ts +1 -0
  25. package/dist/dts/fixtures/when/main.d.ts +1 -0
  26. package/dist/dts/fixtures/when/when.spec.d.ts +1 -0
  27. package/dist/dts/index.d.ts +1 -0
  28. package/dist/dts/interfaces.d.ts +7 -0
  29. package/dist/dts/tsdoc-metadata.json +11 -0
  30. package/dist/esm/components/index.js +1 -0
  31. package/dist/esm/components/template.js +259 -0
  32. package/dist/esm/components/utilities.js +465 -0
  33. package/dist/esm/components/utilities.spec.js +277 -0
  34. package/dist/esm/debug.js +3 -0
  35. package/dist/esm/fixtures/attribute/attribute.spec.js +23 -0
  36. package/dist/esm/fixtures/attribute/main.js +26 -0
  37. package/dist/esm/fixtures/binding/binding.spec.js +23 -0
  38. package/dist/esm/fixtures/binding/main.js +40 -0
  39. package/dist/esm/fixtures/children/children.spec.js +37 -0
  40. package/dist/esm/fixtures/children/main.js +31 -0
  41. package/dist/esm/fixtures/dot-syntax/dot-syntax.spec.js +9 -0
  42. package/dist/esm/fixtures/dot-syntax/main.js +23 -0
  43. package/dist/esm/fixtures/event/event.spec.js +28 -0
  44. package/dist/esm/fixtures/event/main.js +35 -0
  45. package/dist/esm/fixtures/partial/main.js +38 -0
  46. package/dist/esm/fixtures/partial/partial.spec.js +14 -0
  47. package/dist/esm/fixtures/ref/main.js +21 -0
  48. package/dist/esm/fixtures/ref/ref.spec.js +13 -0
  49. package/dist/esm/fixtures/repeat/main.js +27 -0
  50. package/dist/esm/fixtures/repeat/repeat.spec.js +29 -0
  51. package/dist/esm/fixtures/slotted/main.js +29 -0
  52. package/dist/esm/fixtures/slotted/slotted.spec.js +25 -0
  53. package/dist/esm/fixtures/when/main.js +198 -0
  54. package/dist/esm/fixtures/when/when.spec.js +82 -0
  55. package/dist/esm/index.js +4 -0
  56. package/dist/esm/interfaces.js +1 -0
  57. package/dist/esm/tsconfig.tsbuildinfo +1 -0
  58. package/dist/fast-html.api.json +356 -0
  59. package/dist/fast-html.d.ts +78 -0
  60. package/dist/fast-html.untrimmed.d.ts +78 -0
  61. package/package.json +12 -6
  62. package/rules/attribute-directives.yml +38 -0
  63. package/rules/call-expression-with-event-argument.yml +41 -0
  64. package/rules/member-expression.yml +33 -0
  65. package/rules/tag-function-to-template-literal.yml +16 -0
  66. package/CHANGELOG.json +0 -26
  67. package/CHANGELOG.md +0 -14
  68. package/docs/api-report.api.md +0 -18
  69. package/webpack.common.config.js +0 -18
@@ -0,0 +1,465 @@
1
+ const openClientSideBinding = "{";
2
+ const closeClientSideBinding = "}";
3
+ const openContentBinding = "{{";
4
+ const closeContentBinding = "}}";
5
+ const openUnescapedBinding = "{{{";
6
+ const closeUnescapedBinding = "}}}";
7
+ const openTagStart = "<f-";
8
+ const tagEnd = ">";
9
+ const closeTagStart = "</f-";
10
+ const attributeDirectivePrefix = "f-";
11
+ const startInnerHTMLDiv = `<div :innerHTML="{{`;
12
+ const startInnerHTMLDivLength = startInnerHTMLDiv.length;
13
+ const endInnerHTMLDiv = `}}"></div>`;
14
+ const endInnerHTMLDivLength = endInnerHTMLDiv.length;
15
+ /**
16
+ * Get the index of the next matching tag
17
+ * @param openingTagStartSlice - The slice starting from the opening tag
18
+ * @param openingTag - The opening tag string
19
+ * @param closingTag - The closing tag
20
+ * @param openingTagStartIndex - The opening tag start index derived from the innerHTML
21
+ * @returns index
22
+ */
23
+ export function getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex) {
24
+ let tagCount = 1;
25
+ let matchingCloseTagIndex = -1;
26
+ const openingTagLength = openingTag.length;
27
+ const closingTagLength = closingTag.length;
28
+ let nextSlice = openingTagStartSlice.slice(openingTagLength);
29
+ let nextOpenTag = nextSlice.indexOf(openingTag);
30
+ let nextCloseTag = nextSlice.indexOf(closingTag);
31
+ let tagOffset = openingTagStartIndex + openingTagLength;
32
+ do {
33
+ // if a closing tag has been found for the last open tag, decrement the tag count
34
+ if (nextOpenTag > nextCloseTag || nextOpenTag === -1) {
35
+ tagCount--;
36
+ if (tagCount === 0) {
37
+ matchingCloseTagIndex = nextCloseTag + tagOffset;
38
+ break;
39
+ }
40
+ tagOffset += nextCloseTag + closingTagLength;
41
+ nextSlice = nextSlice.slice(nextCloseTag + closingTagLength);
42
+ nextOpenTag = nextSlice.indexOf(openingTag);
43
+ nextCloseTag = nextSlice.indexOf(closingTag);
44
+ }
45
+ else if (nextOpenTag !== -1) {
46
+ tagCount++;
47
+ tagOffset += nextOpenTag + openingTagLength;
48
+ nextSlice = nextSlice.slice(nextOpenTag + openingTagLength);
49
+ nextOpenTag = nextSlice.indexOf(openingTag);
50
+ nextCloseTag = nextSlice.indexOf(closingTag);
51
+ }
52
+ if (tagCount === 0) {
53
+ matchingCloseTagIndex = nextCloseTag + tagOffset;
54
+ break;
55
+ }
56
+ } while (tagCount > 0);
57
+ return matchingCloseTagIndex;
58
+ }
59
+ /**
60
+ * Get the next directive
61
+ * @param innerHTML - The innerHTML string to evaluate
62
+ * @returns DirectiveBehaviorConfig - A configuration object
63
+ */
64
+ function getNextDirectiveBehavior(innerHTML) {
65
+ const openingTagStartIndex = innerHTML.indexOf(openTagStart);
66
+ const openingTagStartSlice = innerHTML.slice(openingTagStartIndex);
67
+ const openingTagEndIndex = // account for f-when which may include >= or > as operators, but will always include a condition attr
68
+ openingTagStartSlice.indexOf(`"${tagEnd}`) + openingTagStartIndex + 2;
69
+ const directiveTag = innerHTML
70
+ .slice(openingTagStartIndex + 3, openingTagEndIndex - 1)
71
+ .split(" ")[0];
72
+ const directiveValue = getNextDataBindingBehavior(innerHTML);
73
+ const openingTag = `${openTagStart}${directiveTag}`;
74
+ const closingTag = `${closeTagStart}${directiveTag}${tagEnd}`;
75
+ const matchingCloseTagIndex = getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex);
76
+ return {
77
+ type: "templateDirective",
78
+ name: directiveTag,
79
+ value: innerHTML.slice(directiveValue.openingEndIndex, directiveValue.closingStartIndex),
80
+ openingTagStartIndex,
81
+ openingTagEndIndex,
82
+ closingTagStartIndex: matchingCloseTagIndex,
83
+ closingTagEndIndex: matchingCloseTagIndex + closingTag.length,
84
+ };
85
+ }
86
+ /**
87
+ * Determine if this binding is an attribute binding
88
+ * @param innerHTML - The innerHTML string to evaluate
89
+ * @param openingStartIndex - The index of the binding opening marker
90
+ * @returns boolean
91
+ */
92
+ function isAttribute(innerHTML, openingStartIndex) {
93
+ return innerHTML.slice(openingStartIndex - 2, openingStartIndex - 1) === "=";
94
+ }
95
+ /**
96
+ * Determine if this binding is an attribute directive binding
97
+ * @param innerHTML - The innerHTML string to evaluate
98
+ * @param openingStartIndex - The index of the binding opening marker
99
+ * @returns boolean
100
+ */
101
+ function isAttributeDirective(innerHTML, openingStartIndex) {
102
+ const splitHTML = innerHTML.slice(0, openingStartIndex - 2).split(" ");
103
+ return splitHTML[splitHTML.length - 1].startsWith(attributeDirectivePrefix);
104
+ }
105
+ /**
106
+ * Get the attribute binding config
107
+ * @param innerHTML - The innerHTML string to evaluate
108
+ * @param config - The base configuration of the binding
109
+ * @returns AttributeDataBindingBehaviorConfig
110
+ */
111
+ function getAttributeDataBindingConfig(innerHTML, config) {
112
+ const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
113
+ const firstCharOfAttribute = splitInnerHTML[splitInnerHTML.length - 1][0];
114
+ const aspect = firstCharOfAttribute === "?" ||
115
+ firstCharOfAttribute === "@" ||
116
+ firstCharOfAttribute === ":"
117
+ ? firstCharOfAttribute
118
+ : null;
119
+ return Object.assign(Object.assign({}, config), { subtype: "attribute", aspect });
120
+ }
121
+ /**
122
+ * Get the attribute directive binding config
123
+ * @param innerHTML - The innerHTML string to evaluate
124
+ * @param config - The base configuration of the binding
125
+ * @returns AttributeDirectiveBindingBehaviorConfig
126
+ */
127
+ function getAttributeDirectiveDataBindingConfig(innerHTML, config) {
128
+ const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
129
+ const lastItem = splitInnerHTML[splitInnerHTML.length - 1];
130
+ const equals = lastItem.indexOf("=");
131
+ const name = lastItem.slice(2, equals);
132
+ return Object.assign(Object.assign({}, config), { subtype: "attributeDirective", name: name });
133
+ }
134
+ /**
135
+ * Get the content data binding config
136
+ * @param config - The base configuration of the binding
137
+ * @returns ContentDataBindingBehaviorConfig
138
+ */
139
+ function getContentDataBindingConfig(config) {
140
+ return Object.assign(Object.assign({}, config), { subtype: "content" });
141
+ }
142
+ function getIndexAndBindingTypeOfNextDataBindingBehavior(innerHTML) {
143
+ // {{{}}} binding
144
+ const openingUnescapedStartIndex = innerHTML.indexOf(openUnescapedBinding);
145
+ const closingUnescapedStartIndex = innerHTML.indexOf(closeUnescapedBinding);
146
+ // {{}} binding
147
+ const openingContentStartIndex = innerHTML.indexOf(openContentBinding);
148
+ const closingContentStartIndex = innerHTML.indexOf(closeContentBinding);
149
+ // {} binding
150
+ const openingClientStartIndex = innerHTML.indexOf(openClientSideBinding);
151
+ const closingClientStartIndex = innerHTML.indexOf(closeClientSideBinding);
152
+ if (openingUnescapedStartIndex !== -1 &&
153
+ openingUnescapedStartIndex <= openingContentStartIndex &&
154
+ openingUnescapedStartIndex <= openingClientStartIndex) {
155
+ // is unescaped {{{}}}
156
+ return {
157
+ openingStartIndex: openingUnescapedStartIndex,
158
+ closingStartIndex: closingUnescapedStartIndex,
159
+ bindingType: "unescaped",
160
+ };
161
+ }
162
+ else if (openingContentStartIndex !== -1 &&
163
+ openingContentStartIndex <= openingClientStartIndex) {
164
+ // is default {{}}
165
+ return {
166
+ openingStartIndex: openingContentStartIndex,
167
+ closingStartIndex: closingContentStartIndex,
168
+ bindingType: "default",
169
+ };
170
+ }
171
+ // is client {}
172
+ return {
173
+ openingStartIndex: openingClientStartIndex,
174
+ closingStartIndex: closingClientStartIndex,
175
+ bindingType: "client",
176
+ };
177
+ }
178
+ /**
179
+ * Get the next data binding
180
+ * @param innerHTML - The innerHTML string to evaluate
181
+ * @returns DataBindingBehaviorConfig - A configuration object
182
+ */
183
+ function getNextDataBindingBehavior(innerHTML) {
184
+ const { openingStartIndex, closingStartIndex, bindingType } = getIndexAndBindingTypeOfNextDataBindingBehavior(innerHTML);
185
+ const bindingLength = bindingType === "client" ? 1 : bindingType === "default" ? 2 : 3;
186
+ const partialConfig = {
187
+ type: "dataBinding",
188
+ bindingType,
189
+ openingStartIndex,
190
+ openingEndIndex: openingStartIndex + bindingLength,
191
+ closingStartIndex,
192
+ closingEndIndex: closingStartIndex + bindingLength,
193
+ };
194
+ return isAttributeDirective(innerHTML, openingStartIndex)
195
+ ? getAttributeDirectiveDataBindingConfig(innerHTML, partialConfig)
196
+ : isAttribute(innerHTML, openingStartIndex)
197
+ ? getAttributeDataBindingConfig(innerHTML, partialConfig)
198
+ : getContentDataBindingConfig(partialConfig);
199
+ }
200
+ /**
201
+ * Get the next behavior
202
+ * @param innerHTML - The innerHTML string to evaluate
203
+ * @returns DataBindingBehaviorConfig | DirectiveBehaviorConfig | null - A configuration object or null
204
+ */
205
+ export function getNextBehavior(innerHTML) {
206
+ const dataBindingOpen = innerHTML.indexOf(openClientSideBinding); // client side binding will capture all bindings starting with "{"
207
+ const directiveBindingOpen = innerHTML.indexOf(openTagStart);
208
+ if (dataBindingOpen === -1 && directiveBindingOpen === -1) {
209
+ return null;
210
+ }
211
+ if (directiveBindingOpen !== -1 && dataBindingOpen > directiveBindingOpen) {
212
+ return getNextDirectiveBehavior(innerHTML);
213
+ }
214
+ return getNextDataBindingBehavior(innerHTML);
215
+ }
216
+ /**
217
+ * Gets all the partials with their IDs
218
+ * @param innerHTML - The innerHTML string to evaluate
219
+ * @param offset - The index offset from the innerHTML
220
+ * @param partials - The partials found
221
+ * @returns {[key: string]: PartialTemplateConfig}
222
+ */
223
+ export function getAllPartials(innerHTML, offset = 0, partials = {}) {
224
+ const openingTag = `${openTagStart}partial`;
225
+ const openingTagStartIndex = innerHTML.indexOf(openingTag);
226
+ if (openingTagStartIndex >= 0) {
227
+ const openingTagStartSlice = innerHTML.slice(openingTagStartIndex);
228
+ const closingTag = `${closeTagStart}partial${tagEnd}`;
229
+ const closingTagLength = closingTag.length;
230
+ const matchingCloseTagIndex = getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex) + closingTagLength;
231
+ const startId = openingTagStartIndex + ' id="'.length + openingTag.length;
232
+ const endId = innerHTML.slice(startId).indexOf('"') + startId;
233
+ const id = innerHTML.slice(startId, endId);
234
+ const openingTagEndIndex = openingTagStartSlice.indexOf(tagEnd) + 1 + openingTagStartIndex;
235
+ const closingTagStartIndex = matchingCloseTagIndex - closingTagLength;
236
+ partials[id] = {
237
+ innerHTML: innerHTML.slice(openingTagEndIndex, closingTagStartIndex),
238
+ startIndex: openingTagEndIndex + offset,
239
+ endIndex: closingTagStartIndex + offset,
240
+ };
241
+ offset += matchingCloseTagIndex;
242
+ return getAllPartials(innerHTML.slice(matchingCloseTagIndex), offset, partials);
243
+ }
244
+ return partials;
245
+ }
246
+ /**
247
+ * Create a function to resolve a value from an object using a path with dot syntax.
248
+ * e.g. "foo.bar"
249
+ * @param path - The dot syntax path to an objects property.
250
+ * @param self - Where the first item in the path path refers to the item itself (used by repeat).
251
+ * @returns A function to access the value from a given path.
252
+ */
253
+ export function pathResolver(path, self = false) {
254
+ let splitPath = path.split(".");
255
+ const usesContext = path.startsWith("../");
256
+ if (self && !usesContext) {
257
+ if (splitPath.length > 1) {
258
+ splitPath = splitPath.slice(1);
259
+ }
260
+ else {
261
+ return (accessibleObject) => {
262
+ return accessibleObject;
263
+ };
264
+ }
265
+ }
266
+ if (splitPath.length === 1 && !usesContext) {
267
+ return (accessibleObject) => {
268
+ return accessibleObject === null || accessibleObject === void 0 ? void 0 : accessibleObject[splitPath[0]];
269
+ };
270
+ }
271
+ return (accessibleObject, context) => {
272
+ if (usesContext) {
273
+ splitPath = [];
274
+ path.split("../").forEach(pathItem => {
275
+ if (pathItem === "") {
276
+ splitPath.unshift("parent");
277
+ }
278
+ else {
279
+ splitPath.push(...pathItem.split("."));
280
+ }
281
+ });
282
+ return splitPath.reduce((previousAccessors, pathItem) => {
283
+ return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
284
+ }, context);
285
+ }
286
+ return splitPath.reduce((previousAccessors, pathItem) => {
287
+ return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
288
+ }, accessibleObject);
289
+ };
290
+ }
291
+ /**
292
+ * Determine if the operand is a value (boolean, number, string) or an accessor.
293
+ * @param operand
294
+ */
295
+ function isOperandValue(operand) {
296
+ try {
297
+ operand = operand.replaceAll("'", '"');
298
+ const value = JSON.parse(operand);
299
+ return {
300
+ value,
301
+ isValue: true,
302
+ };
303
+ }
304
+ catch (e) {
305
+ return {
306
+ value: operand,
307
+ isValue: false,
308
+ };
309
+ }
310
+ }
311
+ /**
312
+ * Gets the expression chain as a configuration object
313
+ * @param value - The binding string value
314
+ * @returns - A configuration object containing information about the expression
315
+ */
316
+ export function getExpressionChain(value) {
317
+ const split = value.split(" ");
318
+ let expressionString = "";
319
+ let chainedExpression;
320
+ // split expressions by chaining operators
321
+ split.forEach((splitItem, index) => {
322
+ if (splitItem === "&&" || splitItem === "||" || splitItem === "&amp;&amp;") {
323
+ chainedExpression = {
324
+ expression: getExpression(expressionString),
325
+ next: Object.assign({ operator: splitItem }, getExpressionChain(split.slice(index + 1).join(" "))),
326
+ };
327
+ }
328
+ else {
329
+ expressionString = `${expressionString ? `${expressionString} ` : ""}${splitItem}`;
330
+ }
331
+ });
332
+ if (chainedExpression) {
333
+ return chainedExpression;
334
+ }
335
+ if (expressionString) {
336
+ return {
337
+ expression: getExpression(expressionString),
338
+ };
339
+ }
340
+ return void 0;
341
+ }
342
+ function getExpression(value) {
343
+ if (value[0] === "!") {
344
+ return {
345
+ operator: "!",
346
+ left: value.slice(1),
347
+ right: null,
348
+ rightIsValue: null,
349
+ };
350
+ }
351
+ const split = value.split(" ");
352
+ if (split.length === 3) {
353
+ const operator = split[1];
354
+ const { value, isValue } = isOperandValue(split[2]);
355
+ return {
356
+ operator,
357
+ left: split[0],
358
+ right: isValue ? value : split[2],
359
+ rightIsValue: isValue,
360
+ };
361
+ }
362
+ return {
363
+ operator: "access",
364
+ left: value,
365
+ right: null,
366
+ rightIsValue: null,
367
+ };
368
+ }
369
+ /**
370
+ * Resolve a single expression
371
+ * @param x - The context
372
+ * @param c - The parent context
373
+ * @param self - Where the first item in the path path refers to the item itself (used by repeat).
374
+ * @param expression - The expression being evaluated
375
+ * @returns - A function resolving the binding for this expression
376
+ */
377
+ function resolveExpression(x, c, self, expression) {
378
+ const { operator, left, right, rightIsValue } = expression;
379
+ switch (operator) {
380
+ case "!":
381
+ return !pathResolver(left, self)(x, c);
382
+ case "==":
383
+ return (pathResolver(left, self)(x, c) ==
384
+ (rightIsValue ? right : pathResolver(right, self)(x, c)));
385
+ case "!=":
386
+ return (pathResolver(left, self)(x, c) !=
387
+ (rightIsValue ? right : pathResolver(right, self)(x, c)));
388
+ case ">=":
389
+ return (pathResolver(left, self)(x, c) >=
390
+ (rightIsValue ? right : pathResolver(right, self)(x, c)));
391
+ case ">":
392
+ return (pathResolver(left, self)(x, c) >
393
+ (rightIsValue ? right : pathResolver(right, self)(x, c)));
394
+ case "<=":
395
+ return (pathResolver(left, self)(x, c) <=
396
+ (rightIsValue ? right : pathResolver(right, self)(x, c)));
397
+ case "<":
398
+ return (pathResolver(left, self)(x, c) <
399
+ (rightIsValue ? right : pathResolver(right, self)(x, c)));
400
+ default:
401
+ return pathResolver(left, self)(x, c);
402
+ }
403
+ }
404
+ /**
405
+ * Resolve a chained expression
406
+ * @param x - The context
407
+ * @param c - The parent context
408
+ * @param self - Where the first item in the path path refers to the item itself (used by repeat).
409
+ * @param expression - The expression being evaluated
410
+ * @param next - The next expression to be chained
411
+ * @returns - A resolved return value for a binding
412
+ */
413
+ function resolveChainedExpression(x, c, self, expression, next) {
414
+ if (next) {
415
+ switch (next.operator) {
416
+ case "&&":
417
+ case "&amp;&amp;":
418
+ return (resolveExpression(x, c, self, expression) &&
419
+ resolveChainedExpression(x, c, self, next.expression, next.next));
420
+ case "||":
421
+ return (resolveExpression(x, c, self, expression) ||
422
+ resolveChainedExpression(x, c, self, next.expression, next.next));
423
+ }
424
+ }
425
+ return resolveExpression(x, c, self, expression);
426
+ }
427
+ /**
428
+ * This is the transform utility for rationalizing declarative HTML syntax
429
+ * with bindings in the ViewTemplate
430
+ * @param innerHTML The innerHTML to transform
431
+ * @param index The index to start the current slice of HTML to evaluate
432
+ */
433
+ export function transformInnerHTML(innerHTML, index = 0) {
434
+ const sliceToEvaluate = innerHTML.slice(index);
435
+ const nextBinding = getNextBehavior(sliceToEvaluate);
436
+ let transformedInnerHTML = innerHTML;
437
+ if (nextBinding && nextBinding.type === "dataBinding") {
438
+ if (nextBinding.bindingType === "unescaped") {
439
+ transformedInnerHTML = `${innerHTML.slice(0, index)}${sliceToEvaluate.slice(0, nextBinding.openingStartIndex)}${startInnerHTMLDiv}${sliceToEvaluate.slice(nextBinding.openingStartIndex + 3, nextBinding.closingStartIndex)}${endInnerHTMLDiv}${sliceToEvaluate.slice(nextBinding.closingStartIndex + 3)}`;
440
+ return transformInnerHTML(transformedInnerHTML, index +
441
+ startInnerHTMLDivLength +
442
+ endInnerHTMLDivLength +
443
+ nextBinding.closingStartIndex -
444
+ 3);
445
+ }
446
+ else if (nextBinding.bindingType === "client") {
447
+ return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingEndIndex);
448
+ }
449
+ return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingEndIndex);
450
+ }
451
+ else if (nextBinding) {
452
+ return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingTagEndIndex);
453
+ }
454
+ return transformedInnerHTML;
455
+ }
456
+ /**
457
+ * Resolves f-when
458
+ * @param self - Where the first item in the path path refers to the item itself (used by repeat).
459
+ * @param chainedExpression - The chained expression which includes the expression and the next expression
460
+ * if there is another in the chain
461
+ * @returns - A binding that resolves the chained expression logic
462
+ */
463
+ export function resolveWhen(self, { expression, next }) {
464
+ return (x, c) => resolveChainedExpression(x, c, self, expression, next);
465
+ }