@microsoft/fast-html 1.0.0-alpha.4 → 1.0.0-alpha.40

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 (68) hide show
  1. package/README.md +242 -18
  2. package/dist/dts/components/element.d.ts +10 -0
  3. package/dist/dts/components/index.d.ts +3 -1
  4. package/dist/dts/components/observer-map.d.ts +27 -0
  5. package/dist/dts/components/schema.d.ts +144 -0
  6. package/dist/dts/components/template.d.ts +83 -7
  7. package/dist/dts/components/utilities.d.ts +126 -37
  8. package/dist/dts/index.d.ts +1 -1
  9. package/dist/dts/tsdoc-metadata.json +1 -1
  10. package/dist/esm/components/element.js +73 -0
  11. package/dist/esm/components/index.js +3 -1
  12. package/dist/esm/components/observer-map.js +68 -0
  13. package/dist/esm/components/observer-map.spec.js +39 -0
  14. package/dist/esm/components/schema.js +250 -0
  15. package/dist/esm/components/schema.spec.js +484 -0
  16. package/dist/esm/components/template.js +235 -213
  17. package/dist/esm/components/utilities.js +990 -64
  18. package/dist/esm/components/utilities.spec.js +522 -93
  19. package/dist/esm/index.js +1 -1
  20. package/dist/fast-html.api.json +350 -1
  21. package/dist/fast-html.d.ts +283 -6
  22. package/dist/fast-html.untrimmed.d.ts +283 -6
  23. package/package.json +27 -38
  24. package/rules/attribute-directives.yml +38 -0
  25. package/rules/call-expression-with-event-argument.yml +41 -0
  26. package/rules/member-expression.yml +33 -0
  27. package/rules/tag-function-to-template-literal.yml +16 -0
  28. package/dist/dts/fixtures/binding/binding.spec.d.ts +0 -1
  29. package/dist/dts/fixtures/binding/main.d.ts +0 -1
  30. package/dist/dts/fixtures/children/children.spec.d.ts +0 -1
  31. package/dist/dts/fixtures/children/main.d.ts +0 -1
  32. package/dist/dts/fixtures/dot-syntax/dot-syntax.spec.d.ts +0 -1
  33. package/dist/dts/fixtures/dot-syntax/main.d.ts +0 -1
  34. package/dist/dts/fixtures/event/event.spec.d.ts +0 -1
  35. package/dist/dts/fixtures/event/main.d.ts +0 -1
  36. package/dist/dts/fixtures/partial/main.d.ts +0 -1
  37. package/dist/dts/fixtures/partial/partial.spec.d.ts +0 -1
  38. package/dist/dts/fixtures/ref/main.d.ts +0 -1
  39. package/dist/dts/fixtures/ref/ref.spec.d.ts +0 -1
  40. package/dist/dts/fixtures/repeat/main.d.ts +0 -1
  41. package/dist/dts/fixtures/repeat/repeat.spec.d.ts +0 -1
  42. package/dist/dts/fixtures/slotted/main.d.ts +0 -1
  43. package/dist/dts/fixtures/slotted/slotted.spec.d.ts +0 -1
  44. package/dist/dts/fixtures/when/main.d.ts +0 -1
  45. package/dist/dts/fixtures/when/when.spec.d.ts +0 -1
  46. package/dist/esm/fixtures/attribute/attribute.spec.js +0 -23
  47. package/dist/esm/fixtures/attribute/main.js +0 -19
  48. package/dist/esm/fixtures/binding/binding.spec.js +0 -17
  49. package/dist/esm/fixtures/binding/main.js +0 -19
  50. package/dist/esm/fixtures/children/children.spec.js +0 -33
  51. package/dist/esm/fixtures/children/main.js +0 -24
  52. package/dist/esm/fixtures/dot-syntax/dot-syntax.spec.js +0 -9
  53. package/dist/esm/fixtures/dot-syntax/main.js +0 -16
  54. package/dist/esm/fixtures/event/event.spec.js +0 -12
  55. package/dist/esm/fixtures/event/main.js +0 -16
  56. package/dist/esm/fixtures/partial/main.js +0 -31
  57. package/dist/esm/fixtures/partial/partial.spec.js +0 -14
  58. package/dist/esm/fixtures/ref/main.js +0 -14
  59. package/dist/esm/fixtures/ref/ref.spec.js +0 -13
  60. package/dist/esm/fixtures/repeat/main.js +0 -19
  61. package/dist/esm/fixtures/repeat/repeat.spec.js +0 -26
  62. package/dist/esm/fixtures/slotted/main.js +0 -22
  63. package/dist/esm/fixtures/slotted/slotted.spec.js +0 -25
  64. package/dist/esm/fixtures/when/main.js +0 -146
  65. package/dist/esm/fixtures/when/when.spec.js +0 -82
  66. package/dist/esm/tsconfig.tsbuildinfo +0 -1
  67. /package/dist/dts/{fixtures/attribute/attribute.spec.d.ts → components/observer-map.spec.d.ts} +0 -0
  68. /package/dist/dts/{fixtures/attribute/main.d.ts → components/schema.spec.d.ts} +0 -0
@@ -1,45 +1,90 @@
1
- import { __awaiter } from "tslib";
2
1
  import { expect, test } from "@playwright/test";
3
- import { getNextBehavior, getAllPartials, getIndexOfNextMatchingTag, pathResolver } from "./utilities.js";
4
- test.describe("utilities", () => __awaiter(void 0, void 0, void 0, function* () {
5
- test.describe("content", () => __awaiter(void 0, void 0, void 0, function* () {
6
- test("get the next content binding", () => __awaiter(void 0, void 0, void 0, function* () {
2
+ import { refPropertyName, Schema } from "./schema.js";
3
+ import { getNextBehavior, getIndexOfNextMatchingTag, pathResolver, transformInnerHTML, getExpressionChain, extractPathsFromChainedExpression, getChildrenMap, findDef, resolveWhen, } from "./utilities.js";
4
+ test.describe("utilities", async () => {
5
+ test.describe("content", async () => {
6
+ test("get the next content binding", async () => {
7
7
  const innerHTML = "{{text}}";
8
8
  const templateResult = getNextBehavior(innerHTML);
9
9
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
10
10
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("content");
11
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.bindingType).toEqual("default");
11
12
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingStartIndex).toEqual(0);
12
13
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingEndIndex).toEqual(2);
13
14
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(6);
14
15
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingEndIndex).toEqual(8);
15
- }));
16
- }));
17
- test.describe("attributes", () => __awaiter(void 0, void 0, void 0, function* () {
18
- test("get the next attribute binding", () => __awaiter(void 0, void 0, void 0, function* () {
16
+ });
17
+ });
18
+ test.describe("attributes", async () => {
19
+ test("get the next attribute binding", async () => {
19
20
  const innerHTML = "<input type=\"{{type}}\" disabled>";
20
21
  const templateResult = getNextBehavior(innerHTML);
21
22
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
22
23
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("attribute");
23
24
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.aspect).toEqual(null);
25
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.bindingType).toEqual("default");
24
26
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingStartIndex).toEqual(13);
25
27
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingEndIndex).toEqual(15);
26
28
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(19);
27
29
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingEndIndex).toEqual(21);
28
- }));
29
- test("get the next attribute event binding", () => __awaiter(void 0, void 0, void 0, function* () {
30
- const innerHTML = "<input @click=\"{{handleClick()}}\">";
30
+ });
31
+ test("get the next attribute event binding", async () => {
32
+ const innerHTML = "<input @click=\"{handleClick()}\">";
31
33
  const templateResult = getNextBehavior(innerHTML);
32
34
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
33
35
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("attribute");
34
36
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.aspect).toEqual("@");
37
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.bindingType).toEqual("client");
35
38
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingStartIndex).toEqual(15);
36
- expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingEndIndex).toEqual(17);
37
- expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(30);
38
- expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingEndIndex).toEqual(32);
39
- }));
40
- }));
41
- test.describe("templates", () => __awaiter(void 0, void 0, void 0, function* () {
42
- test("when directive", () => __awaiter(void 0, void 0, void 0, function* () {
39
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingEndIndex).toEqual(16);
40
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(29);
41
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingEndIndex).toEqual(30);
42
+ });
43
+ test("skip single-brace content bindings (e.g. CSS braces)", async () => {
44
+ const innerHTML = "<style>.foo { color: red }</style>";
45
+ const templateResult = getNextBehavior(innerHTML);
46
+ expect(templateResult).toBeNull();
47
+ });
48
+ test("skip single-brace non-event, non-property attribute bindings", async () => {
49
+ const innerHTML1 = "<input type=\"{type}\">";
50
+ const templateResult1 = getNextBehavior(innerHTML1);
51
+ expect(templateResult1).toBeNull();
52
+ const innerHTML2 = "<input ?disabled=\"{disabled}\">";
53
+ const templateResult2 = getNextBehavior(innerHTML2);
54
+ expect(templateResult2).toBeNull();
55
+ });
56
+ test("find double-brace binding after skipped single-brace content", async () => {
57
+ const innerHTML = "<style>.foo { color: red } .bar { color: blue }</style><span>{{name}}</span>";
58
+ const templateResult = getNextBehavior(innerHTML);
59
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
60
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("content");
61
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.bindingType).toEqual("default");
62
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingStartIndex).toEqual(61);
63
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(67);
64
+ });
65
+ test("find event binding after skipped single-brace content", async () => {
66
+ const innerHTML = "<style>.foo { color: red }</style><button @click=\"{handler()}\">";
67
+ const templateResult = getNextBehavior(innerHTML);
68
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
69
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("attribute");
70
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.aspect).toEqual("@");
71
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.bindingType).toEqual("client");
72
+ });
73
+ test("find property binding after skipped single-brace content", async () => {
74
+ const innerHTML = "<style>.foo { color: red } .bar { color: blue }</style><button :value=\"{someValue}\">";
75
+ const templateResult = getNextBehavior(innerHTML);
76
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
77
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("attribute");
78
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.aspect).toEqual(":");
79
+ expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.bindingType).toEqual("client");
80
+ });
81
+ test("ensure if there are expected missing {} this does not cause parsing issues", async () => {
82
+ const innerHTML = "<f-when value=\"missing\">";
83
+ expect(getNextBehavior(innerHTML)).toBeTruthy();
84
+ });
85
+ });
86
+ test.describe("templates", async () => {
87
+ test("when directive", async () => {
43
88
  const innerHTML = "<f-when value=\"{{show}}\">Hello world</f-when>";
44
89
  const templateResult = getNextBehavior(innerHTML);
45
90
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("templateDirective");
@@ -47,8 +92,8 @@ test.describe("utilities", () => __awaiter(void 0, void 0, void 0, function* ()
47
92
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagEndIndex).toEqual(25);
48
93
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagStartIndex).toEqual(36);
49
94
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagEndIndex).toEqual(45);
50
- }));
51
- test("when directive with content", () => __awaiter(void 0, void 0, void 0, function* () {
95
+ });
96
+ test("when directive with content", async () => {
52
97
  const innerHTML = "Hello pluto<f-when value=\"{{show}}\">Hello world</f-when>";
53
98
  const templateResult = getNextBehavior(innerHTML);
54
99
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("templateDirective");
@@ -56,8 +101,8 @@ test.describe("utilities", () => __awaiter(void 0, void 0, void 0, function* ()
56
101
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagEndIndex).toEqual(36);
57
102
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagStartIndex).toEqual(47);
58
103
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagEndIndex).toEqual(56);
59
- }));
60
- test("when directive with binding", () => __awaiter(void 0, void 0, void 0, function* () {
104
+ });
105
+ test("when directive with binding", async () => {
61
106
  const innerHTML = "<f-when value=\"{{show}}\">{{text}}</f-when>";
62
107
  const templateResult = getNextBehavior(innerHTML);
63
108
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("templateDirective");
@@ -65,96 +110,480 @@ test.describe("utilities", () => __awaiter(void 0, void 0, void 0, function* ()
65
110
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagEndIndex).toEqual(25);
66
111
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagStartIndex).toEqual(33);
67
112
  expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagEndIndex).toEqual(42);
68
- }));
69
- }));
70
- test.describe("attributes", () => __awaiter(void 0, void 0, void 0, function* () {
71
- test("children directive", () => __awaiter(void 0, void 0, void 0, function* () {
72
- const innerHTML = "<ul f-children=\"{{list}}\"></ul>";
113
+ });
114
+ });
115
+ test.describe("attributes", async () => {
116
+ test("children directive", async () => {
117
+ const innerHTML = "<ul f-children=\"{list}\"></ul>";
73
118
  const result = getNextBehavior(innerHTML);
74
119
  expect(result === null || result === void 0 ? void 0 : result.type).toEqual("dataBinding");
75
120
  expect(result === null || result === void 0 ? void 0 : result.subtype).toEqual("attributeDirective");
76
121
  expect(result === null || result === void 0 ? void 0 : result.name).toEqual("children");
122
+ expect(result === null || result === void 0 ? void 0 : result.bindingType).toEqual("client");
77
123
  expect(result === null || result === void 0 ? void 0 : result.openingStartIndex).toEqual(16);
78
- expect(result === null || result === void 0 ? void 0 : result.openingEndIndex).toEqual(18);
79
- expect(result === null || result === void 0 ? void 0 : result.closingStartIndex).toEqual(22);
80
- expect(result === null || result === void 0 ? void 0 : result.closingEndIndex).toEqual(24);
81
- }));
82
- test("slotted directive", () => __awaiter(void 0, void 0, void 0, function* () {
83
- const innerHTML = "<slot f-slotted=\"{{slottedNodes}}\"></slot>";
124
+ expect(result === null || result === void 0 ? void 0 : result.openingEndIndex).toEqual(17);
125
+ expect(result === null || result === void 0 ? void 0 : result.closingStartIndex).toEqual(21);
126
+ expect(result === null || result === void 0 ? void 0 : result.closingEndIndex).toEqual(22);
127
+ });
128
+ test("slotted directive", async () => {
129
+ const innerHTML = "<slot f-slotted=\"{slottedNodes}\"></slot>";
84
130
  const result = getNextBehavior(innerHTML);
85
131
  expect(result === null || result === void 0 ? void 0 : result.type).toEqual("dataBinding");
86
132
  expect(result === null || result === void 0 ? void 0 : result.subtype).toEqual("attributeDirective");
87
133
  expect(result === null || result === void 0 ? void 0 : result.name).toEqual("slotted");
134
+ expect(result === null || result === void 0 ? void 0 : result.bindingType).toEqual("client");
88
135
  expect(result === null || result === void 0 ? void 0 : result.openingStartIndex).toEqual(17);
89
- expect(result === null || result === void 0 ? void 0 : result.openingEndIndex).toEqual(19);
90
- expect(result === null || result === void 0 ? void 0 : result.closingStartIndex).toEqual(31);
91
- expect(result === null || result === void 0 ? void 0 : result.closingEndIndex).toEqual(33);
92
- }));
93
- test("ref directive", () => __awaiter(void 0, void 0, void 0, function* () {
94
- const innerHTML = "<video f-ref=\"{{video}}\"></video>";
136
+ expect(result === null || result === void 0 ? void 0 : result.openingEndIndex).toEqual(18);
137
+ expect(result === null || result === void 0 ? void 0 : result.closingStartIndex).toEqual(30);
138
+ expect(result === null || result === void 0 ? void 0 : result.closingEndIndex).toEqual(31);
139
+ });
140
+ test("ref directive", async () => {
141
+ const innerHTML = "<video f-ref=\"{video}\"></video>";
95
142
  const result = getNextBehavior(innerHTML);
96
143
  expect(result === null || result === void 0 ? void 0 : result.type).toEqual("dataBinding");
97
144
  expect(result === null || result === void 0 ? void 0 : result.subtype).toEqual("attributeDirective");
98
145
  expect(result === null || result === void 0 ? void 0 : result.name).toEqual("ref");
146
+ expect(result === null || result === void 0 ? void 0 : result.bindingType).toEqual("client");
99
147
  expect(result === null || result === void 0 ? void 0 : result.openingStartIndex).toEqual(14);
100
- expect(result === null || result === void 0 ? void 0 : result.openingEndIndex).toEqual(16);
101
- expect(result === null || result === void 0 ? void 0 : result.closingStartIndex).toEqual(21);
102
- expect(result === null || result === void 0 ? void 0 : result.closingEndIndex).toEqual(23);
103
- }));
104
- }));
105
- test.describe("partials", () => __awaiter(void 0, void 0, void 0, function* () {
106
- test("get a single partial", () => __awaiter(void 0, void 0, void 0, function* () {
107
- const partialContent = "{{text}}";
108
- const partial = `<f-partial id="foo">${partialContent}</f-partial>`;
109
- const allPartials = getAllPartials(partial);
110
- expect(allPartials.foo.innerHTML).toEqual(partialContent);
111
- expect(allPartials.foo.startIndex).toEqual(20);
112
- expect(allPartials.foo.endIndex).toEqual(28);
113
- }));
114
- test("get multiple partials", () => __awaiter(void 0, void 0, void 0, function* () {
115
- const partial1Content = "{{text}}";
116
- const partial2Content = "{{othertext}}";
117
- const partial1 = `<f-partial id="foo">${partial1Content}</f-partial>`;
118
- const partial2 = `<f-partial id="foobar">${partial2Content}</f-partial>`;
119
- const allPartials = getAllPartials(`${partial1}${partial2}`);
120
- expect(allPartials.foo.innerHTML).toEqual(partial1Content);
121
- expect(allPartials.foo.startIndex).toEqual(20);
122
- expect(allPartials.foo.endIndex).toEqual(28);
123
- expect(allPartials.foobar.innerHTML).toEqual(partial2Content);
124
- expect(allPartials.foobar.startIndex).toEqual(63);
125
- expect(allPartials.foobar.endIndex).toEqual(76);
126
- }));
127
- }));
128
- test.describe("getIndexOfNextMatchingTag", () => __awaiter(void 0, void 0, void 0, function* () {
129
- test("should resolve a single tag", () => __awaiter(void 0, void 0, void 0, function* () {
148
+ expect(result === null || result === void 0 ? void 0 : result.openingEndIndex).toEqual(15);
149
+ expect(result === null || result === void 0 ? void 0 : result.closingStartIndex).toEqual(20);
150
+ expect(result === null || result === void 0 ? void 0 : result.closingEndIndex).toEqual(21);
151
+ });
152
+ });
153
+ test.describe("getIndexOfNextMatchingTag", async () => {
154
+ test("should resolve a single tag", async () => {
130
155
  const index = getIndexOfNextMatchingTag(`<div>Hello world</div>`, `<div`, `</div>`, 0);
131
156
  expect(index).toEqual(16);
132
- }));
133
- test("should resolve when there is a nested tag", () => __awaiter(void 0, void 0, void 0, function* () {
157
+ });
158
+ test("should resolve when there is a nested tag", async () => {
134
159
  const index = getIndexOfNextMatchingTag(`<div><div>Hello world</div></div>`, `<div`, `</div>`, 0);
135
160
  expect(index).toEqual(27);
136
- }));
137
- test("should get adjacent tags", () => __awaiter(void 0, void 0, void 0, function* () {
161
+ });
162
+ test("should get adjacent tags", async () => {
138
163
  const index = getIndexOfNextMatchingTag(`<div>Hello world</div><div>Hello pluto</div>`, `<div`, `</div>`, 0);
139
164
  expect(index).toEqual(16);
140
- }));
141
- test("should add an offset for content before the tag", () => __awaiter(void 0, void 0, void 0, function* () {
165
+ });
166
+ test("should add an offset for content before the tag", async () => {
142
167
  const index = getIndexOfNextMatchingTag(`<div>Hello world</div>`, `<div`, `</div>`, 23);
143
168
  expect(index).toEqual(39);
144
- }));
145
- }));
146
- test.describe("pathResolver", () => __awaiter(void 0, void 0, void 0, function* () {
147
- test("should resolve a path with no nesting", () => __awaiter(void 0, void 0, void 0, function* () {
148
- expect(pathResolver("foo")({ foo: "bar" })).toEqual("bar");
149
- }));
150
- test("should resolve a path with nesting", () => __awaiter(void 0, void 0, void 0, function* () {
151
- expect(pathResolver("foo.bar.bat")({ foo: { bar: { bat: "baz" } } })).toEqual("baz");
152
- }));
153
- test("should resolve a path with no nesting and self reference", () => __awaiter(void 0, void 0, void 0, function* () {
154
- expect(pathResolver("foo", true)("bar")).toEqual("bar");
155
- }));
156
- test("should resolve a path with nesting and self reference", () => __awaiter(void 0, void 0, void 0, function* () {
157
- expect(pathResolver("foo.bar.bat", true)({ bar: { bat: "baz" } })).toEqual("baz");
158
- }));
159
- }));
160
- }));
169
+ });
170
+ });
171
+ test.describe("pathResolver", async () => {
172
+ test("should resolve a path with no nesting", async () => {
173
+ expect(pathResolver("foo", null, 0, {})({ foo: "bar" }, {})).toEqual("bar");
174
+ });
175
+ test("should resolve a path with nesting", async () => {
176
+ expect(pathResolver("foo.bar.bat", null, 0, {})({ foo: { bar: { bat: "baz" } } }, {})).toEqual("baz");
177
+ });
178
+ test("should resolve a path with no nesting and self reference", async () => {
179
+ expect(pathResolver("foo", "foo", 0, {})("bar", {})).toEqual("bar");
180
+ });
181
+ test("should resolve a path with nesting and self reference", async () => {
182
+ expect(pathResolver("foo.bar.bat", "foo", 0, {})({ bar: { bat: "baz" } }, {})).toEqual("baz");
183
+ });
184
+ test("should resolve a path with context", async () => {
185
+ expect(pathResolver("foo", "parent", 1, {})({}, { parent: { foo: "bar" } })).toEqual("bar");
186
+ });
187
+ });
188
+ test.describe("transformInnerHTML", async () => {
189
+ test("should resolve a single unescaped data binding", async () => {
190
+ expect(transformInnerHTML(`{{{html}}}`)).toEqual(`<div :innerHTML="{{html}}"></div>`);
191
+ });
192
+ test("should resolve multiple unescaped data bindings", async () => {
193
+ expect(transformInnerHTML(`{{{foo}}}{{{bar}}}`)).toEqual(`<div :innerHTML="{{foo}}"></div><div :innerHTML="{{bar}}"></div>`);
194
+ });
195
+ test("should resolve an unescaped data bindings in a mix of other data content bindings", async () => {
196
+ expect(transformInnerHTML(`{{text1}}{{{foo}}}{{text2}}{{{bar}}}{{text3}}`)).toEqual(`{{text1}}<div :innerHTML="{{foo}}"></div>{{text2}}<div :innerHTML="{{bar}}"></div>{{text3}}`);
197
+ });
198
+ test("should resolve default data bindings in sequence", async () => {
199
+ expect(transformInnerHTML(`{{text1}}{{text2}}`)).toEqual(`{{text1}}{{text2}}`);
200
+ });
201
+ test("should resolve an unescaped data bindings in a mix of other data attribute bindings and nesting", async () => {
202
+ expect(transformInnerHTML(`<div data-foo="{{text1}}">{{{foo}}}</div><div data-bar="{{text2}}"></div>{{{bar}}}<div data-bat="{{text3}}"></div>`)).toEqual(`<div data-foo="{{text1}}"><div :innerHTML="{{foo}}"></div></div><div data-bar="{{text2}}"></div><div :innerHTML="{{bar}}"></div><div data-bat="{{text3}}"></div>`);
203
+ });
204
+ test("should resolve a non-data and non-attribute bindings", async () => {
205
+ expect(transformInnerHTML(`<button @click="{handleNoArgsClick()}">No arguments</button>`)).toEqual(`<button @click="{handleNoArgsClick()}">No arguments</button>`);
206
+ });
207
+ });
208
+ test.describe("getExpressionChain", async () => {
209
+ test("should resolve a truthy value", async () => {
210
+ expect(getExpressionChain("foo")).toEqual({
211
+ expression: {
212
+ operator: "access",
213
+ left: "foo",
214
+ leftIsValue: false,
215
+ right: null,
216
+ rightIsValue: null,
217
+ }
218
+ });
219
+ });
220
+ test("should resolve a falsy value", async () => {
221
+ expect(getExpressionChain("!foo")).toEqual({
222
+ expression: {
223
+ operator: "!",
224
+ left: "foo",
225
+ leftIsValue: false,
226
+ right: null,
227
+ rightIsValue: null,
228
+ }
229
+ });
230
+ });
231
+ test("should resolve a path not equal to string value", async () => {
232
+ expect(getExpressionChain("foo != 'test'")).toEqual({
233
+ expression: {
234
+ operator: "!=",
235
+ left: "foo",
236
+ leftIsValue: false,
237
+ right: "test",
238
+ rightIsValue: true,
239
+ }
240
+ });
241
+ });
242
+ test("should resolve a path not equal to boolean value", async () => {
243
+ expect(getExpressionChain("foo != false")).toEqual({
244
+ expression: {
245
+ operator: "!=",
246
+ left: "foo",
247
+ leftIsValue: false,
248
+ right: false,
249
+ rightIsValue: true,
250
+ }
251
+ });
252
+ });
253
+ test("should resolve a path not equal to numerical value", async () => {
254
+ expect(getExpressionChain("foo != 5")).toEqual({
255
+ expression: {
256
+ operator: "!=",
257
+ left: "foo",
258
+ leftIsValue: false,
259
+ right: 5,
260
+ rightIsValue: true,
261
+ }
262
+ });
263
+ });
264
+ test("should resolve chained expressions", async () => {
265
+ expect(getExpressionChain("foo != 'bat' && bar == 'baz'")).toEqual({
266
+ expression: {
267
+ operator: "!=",
268
+ left: "foo",
269
+ leftIsValue: false,
270
+ right: "bat",
271
+ rightIsValue: true,
272
+ },
273
+ next: {
274
+ operator: "&&",
275
+ expression: {
276
+ operator: "==",
277
+ left: "bar",
278
+ leftIsValue: false,
279
+ right: "baz",
280
+ rightIsValue: true,
281
+ }
282
+ }
283
+ });
284
+ expect(getExpressionChain("foo && bar")).toEqual({
285
+ expression: {
286
+ operator: "access",
287
+ left: "foo",
288
+ leftIsValue: false,
289
+ right: null,
290
+ rightIsValue: null,
291
+ },
292
+ next: {
293
+ operator: "&&",
294
+ expression: {
295
+ operator: "access",
296
+ left: "bar",
297
+ leftIsValue: false,
298
+ right: null,
299
+ rightIsValue: null,
300
+ }
301
+ }
302
+ });
303
+ });
304
+ });
305
+ test.describe("extractPathsFromChainedExpression", async () => {
306
+ test("should extract paths from simple access expression", async () => {
307
+ const expressionChain = getExpressionChain("user");
308
+ expect(expressionChain).toBeDefined();
309
+ const paths = extractPathsFromChainedExpression(expressionChain);
310
+ expect(paths.size).toEqual(1);
311
+ expect(paths.has("user")).toBe(true);
312
+ });
313
+ test("should extract paths from dot notation expression", async () => {
314
+ const expressionChain = getExpressionChain("user.name");
315
+ expect(expressionChain).toBeDefined();
316
+ const paths = extractPathsFromChainedExpression(expressionChain);
317
+ expect(paths.size).toEqual(1);
318
+ expect(paths.has("user.name")).toBe(true);
319
+ });
320
+ test("should extract paths from comparison with literal values", async () => {
321
+ const expressionChain = getExpressionChain("user.age > 18");
322
+ expect(expressionChain).toBeDefined();
323
+ const paths = extractPathsFromChainedExpression(expressionChain);
324
+ expect(paths.size).toEqual(1);
325
+ expect(paths.has("user.age")).toBe(true);
326
+ });
327
+ test("should extract paths from comparison between two properties", async () => {
328
+ const expressionChain = getExpressionChain("user.age >= admin.minAge");
329
+ expect(expressionChain).toBeDefined();
330
+ const paths = extractPathsFromChainedExpression(expressionChain);
331
+ expect(paths.size).toEqual(2);
332
+ expect(paths.has("user.age")).toBe(true);
333
+ expect(paths.has("admin.minAge")).toBe(true);
334
+ });
335
+ test("should extract paths from chained AND expressions", async () => {
336
+ const expressionChain = getExpressionChain("isActive && user.name");
337
+ expect(expressionChain).toBeDefined();
338
+ const paths = extractPathsFromChainedExpression(expressionChain);
339
+ expect(paths.size).toEqual(2);
340
+ expect(paths.has("isActive")).toBe(true);
341
+ expect(paths.has("user.name")).toBe(true);
342
+ });
343
+ test("should extract paths from chained OR expressions", async () => {
344
+ const expressionChain = getExpressionChain("user.isAdmin || permissions.canEdit");
345
+ expect(expressionChain).toBeDefined();
346
+ const paths = extractPathsFromChainedExpression(expressionChain);
347
+ expect(paths.size).toEqual(2);
348
+ expect(paths.has("user.isAdmin")).toBe(true);
349
+ expect(paths.has("permissions.canEdit")).toBe(true);
350
+ });
351
+ test("should extract paths from complex chained expressions", async () => {
352
+ const expressionChain = getExpressionChain("user.age > 18 && user.status == 'active' || admin.override");
353
+ expect(expressionChain).toBeDefined();
354
+ const paths = extractPathsFromChainedExpression(expressionChain);
355
+ expect(paths.size).toEqual(3);
356
+ expect(paths.has("user.age")).toBe(true);
357
+ expect(paths.has("user.status")).toBe(true);
358
+ expect(paths.has("admin.override")).toBe(true);
359
+ });
360
+ test("should extract paths from NOT expressions", async () => {
361
+ const expressionChain = getExpressionChain("!user.isDisabled");
362
+ expect(expressionChain).toBeDefined();
363
+ const paths = extractPathsFromChainedExpression(expressionChain);
364
+ expect(paths.size).toEqual(1);
365
+ expect(paths.has("user.isDisabled")).toBe(true);
366
+ });
367
+ test("should handle expressions with only literal values", async () => {
368
+ const expressionChain = getExpressionChain("5 > 3");
369
+ expect(expressionChain).toBeDefined();
370
+ const paths = extractPathsFromChainedExpression(expressionChain);
371
+ expect(paths.size).toEqual(0);
372
+ });
373
+ test("should handle mixed literal and property expressions", async () => {
374
+ const expressionChain = getExpressionChain("count > 0 && status == 'ready'");
375
+ expect(expressionChain).toBeDefined();
376
+ const paths = extractPathsFromChainedExpression(expressionChain);
377
+ expect(paths.size).toEqual(2);
378
+ expect(paths.has("count")).toBe(true);
379
+ expect(paths.has("status")).toBe(true);
380
+ });
381
+ test("should deduplicate identical paths", async () => {
382
+ const expressionChain = getExpressionChain("user.name && user.name != 'anonymous'");
383
+ expect(expressionChain).toBeDefined();
384
+ const paths = extractPathsFromChainedExpression(expressionChain);
385
+ expect(paths.size).toEqual(1);
386
+ expect(paths.has("user.name")).toBe(true);
387
+ });
388
+ test("should handle HTML entity operators", async () => {
389
+ const expressionChain = getExpressionChain("isValid &amp;&amp; data.ready");
390
+ expect(expressionChain).toBeDefined();
391
+ const paths = extractPathsFromChainedExpression(expressionChain);
392
+ expect(paths.size).toEqual(2);
393
+ expect(paths.has("isValid")).toBe(true);
394
+ expect(paths.has("data.ready")).toBe(true);
395
+ });
396
+ test("should handle deeply nested property paths", async () => {
397
+ const expressionChain = getExpressionChain("app.user.profile.settings.theme");
398
+ expect(expressionChain).toBeDefined();
399
+ const paths = extractPathsFromChainedExpression(expressionChain);
400
+ expect(paths.size).toEqual(1);
401
+ expect(paths.has("app.user.profile.settings.theme")).toBe(true);
402
+ });
403
+ });
404
+ test.describe("resolveWhen - default case truthiness evaluation", async () => {
405
+ // Helper to create a basic schema for testing
406
+ const createTestSchema = (rootPropertyName, propertyName) => {
407
+ const schema = new Schema("test-element");
408
+ schema.addPath({
409
+ rootPropertyName,
410
+ pathConfig: {
411
+ type: "access",
412
+ path: propertyName,
413
+ currentContext: null,
414
+ parentContext: null,
415
+ },
416
+ childrenMap: null,
417
+ });
418
+ return schema;
419
+ };
420
+ test("should evaluate boolean true as truthy", async () => {
421
+ const schema = createTestSchema("testData", "boolTrue");
422
+ const expression = getExpressionChain("boolTrue");
423
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
424
+ const result = resolver({ boolTrue: true }, null);
425
+ expect(result).toBe(true);
426
+ });
427
+ test("should evaluate boolean false as falsy", async () => {
428
+ const schema = createTestSchema("testData", "boolFalse");
429
+ const expression = getExpressionChain("boolFalse");
430
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
431
+ const result = resolver({ boolFalse: false }, null);
432
+ expect(result).toBe(false);
433
+ });
434
+ test("should evaluate number 0 as falsy", async () => {
435
+ const schema = createTestSchema("testData", "numberZero");
436
+ const expression = getExpressionChain("numberZero");
437
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
438
+ const result = resolver({ numberZero: 0 }, null);
439
+ expect(result).toBe(false);
440
+ });
441
+ test("should evaluate positive number as truthy", async () => {
442
+ const schema = createTestSchema("testData", "numberPositive");
443
+ const expression = getExpressionChain("numberPositive");
444
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
445
+ const result = resolver({ numberPositive: 42 }, null);
446
+ expect(result).toBe(true);
447
+ });
448
+ test("should evaluate negative number as truthy", async () => {
449
+ const schema = createTestSchema("testData", "numberNegative");
450
+ const expression = getExpressionChain("numberNegative");
451
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
452
+ const result = resolver({ numberNegative: -5 }, null);
453
+ expect(result).toBe(true);
454
+ });
455
+ test("should evaluate empty string as falsy", async () => {
456
+ const schema = createTestSchema("testData", "stringEmpty");
457
+ const expression = getExpressionChain("stringEmpty");
458
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
459
+ const result = resolver({ stringEmpty: "" }, null);
460
+ expect(result).toBe(false);
461
+ });
462
+ test("should evaluate non-empty string as truthy", async () => {
463
+ const schema = createTestSchema("testData", "stringNonEmpty");
464
+ const expression = getExpressionChain("stringNonEmpty");
465
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
466
+ const result = resolver({ stringNonEmpty: "hello" }, null);
467
+ expect(result).toBe(true);
468
+ });
469
+ test("should evaluate null as falsy", async () => {
470
+ const schema = createTestSchema("testData", "objectNull");
471
+ const expression = getExpressionChain("objectNull");
472
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
473
+ const result = resolver({ objectNull: null }, null);
474
+ expect(result).toBe(false);
475
+ });
476
+ test("should evaluate undefined as falsy", async () => {
477
+ const schema = createTestSchema("testData", "undefinedProp");
478
+ const expression = getExpressionChain("undefinedProp");
479
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
480
+ const result = resolver({ undefinedProp: undefined }, null);
481
+ expect(result).toBe(false);
482
+ });
483
+ test("should evaluate non-null object as truthy", async () => {
484
+ const schema = createTestSchema("testData", "objectNonNull");
485
+ const expression = getExpressionChain("objectNonNull");
486
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
487
+ const result = resolver({ objectNonNull: { foo: "bar" } }, null);
488
+ expect(result).toBe(true);
489
+ });
490
+ test("should evaluate empty array as truthy", async () => {
491
+ const schema = createTestSchema("testData", "arrayEmpty");
492
+ const expression = getExpressionChain("arrayEmpty");
493
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
494
+ const result = resolver({ arrayEmpty: [] }, null);
495
+ expect(result).toBe(true);
496
+ });
497
+ test("should evaluate non-empty array as truthy", async () => {
498
+ const schema = createTestSchema("testData", "arrayNonEmpty");
499
+ const expression = getExpressionChain("arrayNonEmpty");
500
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
501
+ const result = resolver({ arrayNonEmpty: [1, 2, 3] }, null);
502
+ expect(result).toBe(true);
503
+ });
504
+ test("should evaluate string with only whitespace as truthy", async () => {
505
+ const schema = createTestSchema("testData", "stringWhitespace");
506
+ const expression = getExpressionChain("stringWhitespace");
507
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
508
+ const result = resolver({ stringWhitespace: " " }, null);
509
+ expect(result).toBe(true);
510
+ });
511
+ test("should evaluate number NaN as truthy", async () => {
512
+ const schema = createTestSchema("testData", "numberNaN");
513
+ const expression = getExpressionChain("numberNaN");
514
+ const resolver = resolveWhen("testData", expression, null, 0, schema);
515
+ const result = resolver({ numberNaN: NaN }, null);
516
+ expect(result).toBe(true);
517
+ });
518
+ });
519
+ test.describe("getChildrenMap", async () => {
520
+ test("should get a ChildrenMap if an attribute is part of a custom element", async () => {
521
+ const childrenMap = getChildrenMap(`<template><my-element foo="`);
522
+ expect(childrenMap).not.toBeNull();
523
+ expect(childrenMap === null || childrenMap === void 0 ? void 0 : childrenMap.attributeName).toEqual("foo");
524
+ expect(childrenMap === null || childrenMap === void 0 ? void 0 : childrenMap.customElementName).toEqual("my-element");
525
+ });
526
+ test("should not get a ChildrenMap if an attribute is part of a non-custom element", async () => {
527
+ const childrenMap = getChildrenMap(`<template><button foo="`);
528
+ expect(childrenMap).toBeNull();
529
+ });
530
+ test("should remove any aspected attributes from an attribute name", async () => {
531
+ const childrenMap = getChildrenMap(`<template><my-element :foo="`);
532
+ expect(childrenMap).not.toBeNull();
533
+ expect(childrenMap === null || childrenMap === void 0 ? void 0 : childrenMap.attributeName).toEqual("foo");
534
+ expect(childrenMap === null || childrenMap === void 0 ? void 0 : childrenMap.customElementName).toEqual("my-element");
535
+ });
536
+ test("should not get a ChildreMap if the previous string indicates the binding was not an attribute", async () => {
537
+ const childrenMap = getChildrenMap(`<template><my-element>`);
538
+ expect(childrenMap).toBeNull();
539
+ });
540
+ test("should get a ChildrenMap if there are multiple attributes are listed before this attribute", async () => {
541
+ const childrenMap = getChildrenMap(`<template><my-element foo="" bar="" bat="`);
542
+ expect(childrenMap).not.toBeNull();
543
+ expect(childrenMap === null || childrenMap === void 0 ? void 0 : childrenMap.attributeName).toEqual("bat");
544
+ expect(childrenMap === null || childrenMap === void 0 ? void 0 : childrenMap.customElementName).toEqual("my-element");
545
+ });
546
+ });
547
+ test.describe("schema functions", async () => {
548
+ test.describe("findDef", async () => {
549
+ test("should resolve from the root of a schema", async () => {
550
+ expect(findDef({
551
+ [refPropertyName]: "#/$defs/MyType"
552
+ })).toEqual("MyType");
553
+ });
554
+ test("should resolve as null from an anyOf array containing a reference to another component", async () => {
555
+ expect(findDef({
556
+ anyOf: [
557
+ {
558
+ [refPropertyName]: "https://fast.design/schemas/test-element/c.json"
559
+ }
560
+ ]
561
+ })).toEqual(null);
562
+ });
563
+ test("should resolve from an anyOf array containing a reference to a $def", async () => {
564
+ expect(findDef({
565
+ anyOf: [
566
+ {
567
+ [refPropertyName]: "#/$defs/MyType"
568
+ }
569
+ ]
570
+ })).toEqual("MyType");
571
+ });
572
+ test("should resolve from an anyOf array containing a reference to another component and a reference to a $def", async () => {
573
+ expect(findDef({
574
+ anyOf: [
575
+ {
576
+ [refPropertyName]: "https://fast.design/schemas/test-element/c.json"
577
+ },
578
+ {
579
+ [refPropertyName]: "#/$defs/MyType"
580
+ }
581
+ ]
582
+ })).toEqual("MyType");
583
+ });
584
+ test("should resolve as null if not found", async () => {
585
+ expect(findDef({})).toEqual(null);
586
+ });
587
+ });
588
+ });
589
+ });