@microsoft/fast-html 1.0.0-alpha.1 → 1.0.0-alpha.2
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/dts/components/index.d.ts +1 -0
- package/dist/dts/components/template.d.ts +61 -0
- package/dist/dts/components/utilities.d.ts +75 -0
- package/dist/dts/components/utilities.spec.d.ts +1 -0
- package/dist/dts/debug.d.ts +3 -0
- package/dist/dts/fixtures/attribute/attribute.spec.d.ts +1 -0
- package/dist/dts/fixtures/attribute/main.d.ts +1 -0
- package/dist/dts/fixtures/binding/binding.spec.d.ts +1 -0
- package/dist/dts/fixtures/binding/main.d.ts +1 -0
- package/dist/dts/fixtures/children/children.spec.d.ts +1 -0
- package/dist/dts/fixtures/children/main.d.ts +1 -0
- package/dist/dts/fixtures/dot-syntax/dot-syntax.spec.d.ts +1 -0
- package/dist/dts/fixtures/dot-syntax/main.d.ts +1 -0
- package/dist/dts/fixtures/event/event.spec.d.ts +1 -0
- package/dist/dts/fixtures/event/main.d.ts +1 -0
- package/dist/dts/fixtures/partial/main.d.ts +1 -0
- package/dist/dts/fixtures/partial/partial.spec.d.ts +1 -0
- package/dist/dts/fixtures/ref/main.d.ts +1 -0
- package/dist/dts/fixtures/ref/ref.spec.d.ts +1 -0
- package/dist/dts/fixtures/repeat/main.d.ts +1 -0
- package/dist/dts/fixtures/repeat/repeat.spec.d.ts +1 -0
- package/dist/dts/fixtures/slotted/main.d.ts +1 -0
- package/dist/dts/fixtures/slotted/slotted.spec.d.ts +1 -0
- package/dist/dts/fixtures/when/main.d.ts +1 -0
- package/dist/dts/fixtures/when/when.spec.d.ts +1 -0
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/interfaces.d.ts +7 -0
- package/dist/dts/tsdoc-metadata.json +11 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/template.js +223 -0
- package/dist/esm/components/utilities.js +229 -0
- package/dist/esm/components/utilities.spec.js +160 -0
- package/dist/esm/debug.js +3 -0
- package/dist/esm/fixtures/attribute/attribute.spec.js +23 -0
- package/dist/esm/fixtures/attribute/main.js +19 -0
- package/dist/esm/fixtures/binding/binding.spec.js +17 -0
- package/dist/esm/fixtures/binding/main.js +19 -0
- package/dist/esm/fixtures/children/children.spec.js +33 -0
- package/dist/esm/fixtures/children/main.js +24 -0
- package/dist/esm/fixtures/dot-syntax/dot-syntax.spec.js +9 -0
- package/dist/esm/fixtures/dot-syntax/main.js +16 -0
- package/dist/esm/fixtures/event/event.spec.js +12 -0
- package/dist/esm/fixtures/event/main.js +16 -0
- package/dist/esm/fixtures/partial/main.js +31 -0
- package/dist/esm/fixtures/partial/partial.spec.js +14 -0
- package/dist/esm/fixtures/ref/main.js +14 -0
- package/dist/esm/fixtures/ref/ref.spec.js +13 -0
- package/dist/esm/fixtures/repeat/main.js +19 -0
- package/dist/esm/fixtures/repeat/repeat.spec.js +26 -0
- package/dist/esm/fixtures/slotted/main.js +22 -0
- package/dist/esm/fixtures/slotted/slotted.spec.js +25 -0
- package/dist/esm/fixtures/when/main.js +19 -0
- package/dist/esm/fixtures/when/when.spec.js +19 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/interfaces.js +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -0
- package/dist/fast-html.api.json +271 -0
- package/dist/fast-html.d.ts +63 -0
- package/dist/fast-html.untrimmed.d.ts +63 -0
- package/package.json +4 -1
- package/CHANGELOG.json +0 -26
- package/CHANGELOG.md +0 -14
- package/docs/api-report.api.md +0 -18
- package/webpack.common.config.js +0 -18
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
const openBinding = "{{";
|
|
2
|
+
const closeBinding = "}}";
|
|
3
|
+
const openTagStart = "<f-";
|
|
4
|
+
const tagEnd = ">";
|
|
5
|
+
const closeTagStart = "</f-";
|
|
6
|
+
const attributeDirectivePrefix = "f-";
|
|
7
|
+
/**
|
|
8
|
+
* Get the index of the next matching tag
|
|
9
|
+
* @param openingTagStartSlice - The slice starting from the opening tag
|
|
10
|
+
* @param openingTag - The opening tag string
|
|
11
|
+
* @param closingTag - The closing tag
|
|
12
|
+
* @param openingTagStartIndex - The opening tag start index derived from the innerHTML
|
|
13
|
+
* @returns index
|
|
14
|
+
*/
|
|
15
|
+
export function getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex) {
|
|
16
|
+
let tagCount = 1;
|
|
17
|
+
let matchingCloseTagIndex = -1;
|
|
18
|
+
const openingTagLength = openingTag.length;
|
|
19
|
+
const closingTagLength = closingTag.length;
|
|
20
|
+
let nextSlice = openingTagStartSlice.slice(openingTagLength);
|
|
21
|
+
let nextOpenTag = nextSlice.indexOf(openingTag);
|
|
22
|
+
let nextCloseTag = nextSlice.indexOf(closingTag);
|
|
23
|
+
let tagOffset = openingTagStartIndex + openingTagLength;
|
|
24
|
+
do {
|
|
25
|
+
// if a closing tag has been found for the last open tag, decrement the tag count
|
|
26
|
+
if (nextOpenTag > nextCloseTag || nextOpenTag === -1) {
|
|
27
|
+
tagCount--;
|
|
28
|
+
if (tagCount === 0) {
|
|
29
|
+
matchingCloseTagIndex = nextCloseTag + tagOffset;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
tagOffset += nextCloseTag + closingTagLength;
|
|
33
|
+
nextSlice = nextSlice.slice(nextCloseTag + closingTagLength);
|
|
34
|
+
nextOpenTag = nextSlice.indexOf(openingTag);
|
|
35
|
+
nextCloseTag = nextSlice.indexOf(closingTag);
|
|
36
|
+
}
|
|
37
|
+
else if (nextOpenTag !== -1) {
|
|
38
|
+
tagCount++;
|
|
39
|
+
tagOffset += nextOpenTag + openingTagLength;
|
|
40
|
+
nextSlice = nextSlice.slice(nextOpenTag + openingTagLength);
|
|
41
|
+
nextOpenTag = nextSlice.indexOf(openingTag);
|
|
42
|
+
nextCloseTag = nextSlice.indexOf(closingTag);
|
|
43
|
+
}
|
|
44
|
+
if (tagCount === 0) {
|
|
45
|
+
matchingCloseTagIndex = nextCloseTag + tagOffset;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
} while (tagCount > 0);
|
|
49
|
+
return matchingCloseTagIndex;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the next directive
|
|
53
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
54
|
+
* @returns DirectiveBehaviorConfig - A configuration object
|
|
55
|
+
*/
|
|
56
|
+
function getNextDirectiveBehavior(innerHTML) {
|
|
57
|
+
const openingTagStartIndex = innerHTML.indexOf(openTagStart);
|
|
58
|
+
const openingTagStartSlice = innerHTML.slice(openingTagStartIndex);
|
|
59
|
+
const openingTagEndIndex = openingTagStartSlice.indexOf(tagEnd) + openingTagStartIndex + 1;
|
|
60
|
+
const directiveTag = innerHTML
|
|
61
|
+
.slice(openingTagStartIndex + 3, openingTagEndIndex - 1)
|
|
62
|
+
.split(" ")[0];
|
|
63
|
+
const directiveValue = getNextDataBindingBehavior(innerHTML);
|
|
64
|
+
const openingTag = `${openTagStart}${directiveTag}`;
|
|
65
|
+
const closingTag = `${closeTagStart}${directiveTag}${tagEnd}`;
|
|
66
|
+
const matchingCloseTagIndex = getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex);
|
|
67
|
+
return {
|
|
68
|
+
type: "templateDirective",
|
|
69
|
+
name: directiveTag,
|
|
70
|
+
value: innerHTML.slice(directiveValue.openingEndIndex, directiveValue.closingStartIndex),
|
|
71
|
+
openingTagStartIndex,
|
|
72
|
+
openingTagEndIndex,
|
|
73
|
+
closingTagStartIndex: matchingCloseTagIndex,
|
|
74
|
+
closingTagEndIndex: matchingCloseTagIndex + closingTag.length,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Determine if this binding is an attribute binding
|
|
79
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
80
|
+
* @param openingStartIndex - The index of the binding opening marker
|
|
81
|
+
* @returns boolean
|
|
82
|
+
*/
|
|
83
|
+
function isAttribute(innerHTML, openingStartIndex) {
|
|
84
|
+
return innerHTML.slice(openingStartIndex - 2, openingStartIndex - 1) === "=";
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Determine if this binding is an attribute directive 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 isAttributeDirective(innerHTML, openingStartIndex) {
|
|
93
|
+
const splitHTML = innerHTML.slice(0, openingStartIndex - 2).split(" ");
|
|
94
|
+
return splitHTML[splitHTML.length - 1].startsWith(attributeDirectivePrefix);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get the attribute binding config
|
|
98
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
99
|
+
* @param config - The base configuration of the binding
|
|
100
|
+
* @returns AttributeDataBindingBehaviorConfig
|
|
101
|
+
*/
|
|
102
|
+
function getAttributeDataBindingConfig(innerHTML, config) {
|
|
103
|
+
const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
|
|
104
|
+
const firstCharOfAttribute = splitInnerHTML[splitInnerHTML.length - 1][0];
|
|
105
|
+
const aspect = firstCharOfAttribute === "?" ||
|
|
106
|
+
firstCharOfAttribute === "@" ||
|
|
107
|
+
firstCharOfAttribute === ":"
|
|
108
|
+
? firstCharOfAttribute
|
|
109
|
+
: null;
|
|
110
|
+
return Object.assign(Object.assign({}, config), { subtype: "attribute", aspect });
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get the attribute directive binding config
|
|
114
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
115
|
+
* @param config - The base configuration of the binding
|
|
116
|
+
* @returns AttributeDirectiveBindingBehaviorConfig
|
|
117
|
+
*/
|
|
118
|
+
function getAttributeDirectiveDataBindingConfig(innerHTML, config) {
|
|
119
|
+
const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
|
|
120
|
+
const lastItem = splitInnerHTML[splitInnerHTML.length - 1];
|
|
121
|
+
const equals = lastItem.indexOf("=");
|
|
122
|
+
const name = lastItem.slice(2, equals);
|
|
123
|
+
return Object.assign(Object.assign({}, config), { subtype: "attributeDirective", name: name });
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get the content data binding config
|
|
127
|
+
* @param config - The base configuration of the binding
|
|
128
|
+
* @returns ContentDataBindingBehaviorConfig
|
|
129
|
+
*/
|
|
130
|
+
function getContentDataBindingConfig(config) {
|
|
131
|
+
return Object.assign(Object.assign({}, config), { subtype: "content" });
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get the next data binding
|
|
135
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
136
|
+
* @returns DataBindingBehaviorConfig - A configuration object
|
|
137
|
+
*/
|
|
138
|
+
function getNextDataBindingBehavior(innerHTML) {
|
|
139
|
+
const openingStartIndex = innerHTML.indexOf(openBinding);
|
|
140
|
+
const closingStartIndex = innerHTML.indexOf(closeBinding);
|
|
141
|
+
const partialConfig = {
|
|
142
|
+
type: "dataBinding",
|
|
143
|
+
openingStartIndex,
|
|
144
|
+
openingEndIndex: openingStartIndex + 2,
|
|
145
|
+
closingStartIndex,
|
|
146
|
+
closingEndIndex: closingStartIndex + 2,
|
|
147
|
+
};
|
|
148
|
+
return isAttributeDirective(innerHTML, openingStartIndex)
|
|
149
|
+
? getAttributeDirectiveDataBindingConfig(innerHTML, partialConfig)
|
|
150
|
+
: isAttribute(innerHTML, openingStartIndex)
|
|
151
|
+
? getAttributeDataBindingConfig(innerHTML, partialConfig)
|
|
152
|
+
: getContentDataBindingConfig(partialConfig);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get the next behavior
|
|
156
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
157
|
+
* @returns DataBindingBehaviorConfig | DirectiveBehaviorConfig | null - A configuration object or null
|
|
158
|
+
*/
|
|
159
|
+
export function getNextBehavior(innerHTML) {
|
|
160
|
+
const dataBindingOpen = innerHTML.indexOf(openBinding);
|
|
161
|
+
const directiveBindingOpen = innerHTML.indexOf(openTagStart);
|
|
162
|
+
if (dataBindingOpen === -1 && directiveBindingOpen === -1) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
if (directiveBindingOpen !== -1 && dataBindingOpen > directiveBindingOpen) {
|
|
166
|
+
return getNextDirectiveBehavior(innerHTML);
|
|
167
|
+
}
|
|
168
|
+
return getNextDataBindingBehavior(innerHTML);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Gets all the partials with their IDs
|
|
172
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
173
|
+
* @param offset - The index offset from the innerHTML
|
|
174
|
+
* @param partials - The partials found
|
|
175
|
+
* @returns {[key: string]: PartialTemplateConfig}
|
|
176
|
+
*/
|
|
177
|
+
export function getAllPartials(innerHTML, offset = 0, partials = {}) {
|
|
178
|
+
const openingTag = `${openTagStart}partial`;
|
|
179
|
+
const openingTagStartIndex = innerHTML.indexOf(openingTag);
|
|
180
|
+
if (openingTagStartIndex >= 0) {
|
|
181
|
+
const openingTagStartSlice = innerHTML.slice(openingTagStartIndex);
|
|
182
|
+
const closingTag = `${closeTagStart}partial${tagEnd}`;
|
|
183
|
+
const closingTagLength = closingTag.length;
|
|
184
|
+
const matchingCloseTagIndex = getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex) + closingTagLength;
|
|
185
|
+
const startId = openingTagStartIndex + ' id="'.length + openingTag.length;
|
|
186
|
+
const endId = innerHTML.slice(startId).indexOf('"') + startId;
|
|
187
|
+
const id = innerHTML.slice(startId, endId);
|
|
188
|
+
const openingTagEndIndex = openingTagStartSlice.indexOf(">") + 1 + openingTagStartIndex;
|
|
189
|
+
const closingTagStartIndex = matchingCloseTagIndex - closingTagLength;
|
|
190
|
+
partials[id] = {
|
|
191
|
+
innerHTML: innerHTML.slice(openingTagEndIndex, closingTagStartIndex),
|
|
192
|
+
startIndex: openingTagEndIndex + offset,
|
|
193
|
+
endIndex: closingTagStartIndex + offset,
|
|
194
|
+
};
|
|
195
|
+
offset += matchingCloseTagIndex;
|
|
196
|
+
return getAllPartials(innerHTML.slice(matchingCloseTagIndex), offset, partials);
|
|
197
|
+
}
|
|
198
|
+
return partials;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Create a function to resolve a value from an object using a path with dot syntax.
|
|
202
|
+
* e.g. "foo.bar"
|
|
203
|
+
* @param path - The dot syntax path to an objects property.
|
|
204
|
+
* @param self - Where the first item in the path path refers to the item itself (used by repeat).
|
|
205
|
+
* @returns A function to access the value from a given path.
|
|
206
|
+
*/
|
|
207
|
+
export function pathResolver(path, self = false) {
|
|
208
|
+
let splitPath = path.split(".");
|
|
209
|
+
if (self) {
|
|
210
|
+
if (splitPath.length > 1) {
|
|
211
|
+
splitPath = splitPath.slice(1);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
return (accessibleObject) => {
|
|
215
|
+
return accessibleObject;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (splitPath.length === 1) {
|
|
220
|
+
return (accessibleObject) => {
|
|
221
|
+
return accessibleObject === null || accessibleObject === void 0 ? void 0 : accessibleObject[splitPath[0]];
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return (accessibleObject) => {
|
|
225
|
+
return splitPath.reduce((previousAccessors, pathItem) => {
|
|
226
|
+
return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
|
|
227
|
+
}, accessibleObject);
|
|
228
|
+
};
|
|
229
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
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* () {
|
|
7
|
+
const innerHTML = "{{text}}";
|
|
8
|
+
const templateResult = getNextBehavior(innerHTML);
|
|
9
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
|
|
10
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("content");
|
|
11
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingStartIndex).toEqual(0);
|
|
12
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingEndIndex).toEqual(2);
|
|
13
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(6);
|
|
14
|
+
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* () {
|
|
19
|
+
const innerHTML = "<input type=\"{{type}}\" disabled>";
|
|
20
|
+
const templateResult = getNextBehavior(innerHTML);
|
|
21
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
|
|
22
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("attribute");
|
|
23
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.aspect).toEqual(null);
|
|
24
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingStartIndex).toEqual(13);
|
|
25
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingEndIndex).toEqual(15);
|
|
26
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingStartIndex).toEqual(19);
|
|
27
|
+
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()}}\">";
|
|
31
|
+
const templateResult = getNextBehavior(innerHTML);
|
|
32
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("dataBinding");
|
|
33
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.subtype).toEqual("attribute");
|
|
34
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.aspect).toEqual("@");
|
|
35
|
+
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* () {
|
|
43
|
+
const innerHTML = "<f-when value=\"{{show}}\">Hello world</f-when>";
|
|
44
|
+
const templateResult = getNextBehavior(innerHTML);
|
|
45
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("templateDirective");
|
|
46
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagStartIndex).toEqual(0);
|
|
47
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagEndIndex).toEqual(25);
|
|
48
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagStartIndex).toEqual(36);
|
|
49
|
+
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* () {
|
|
52
|
+
const innerHTML = "Hello pluto<f-when value=\"{{show}}\">Hello world</f-when>";
|
|
53
|
+
const templateResult = getNextBehavior(innerHTML);
|
|
54
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("templateDirective");
|
|
55
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagStartIndex).toEqual(11);
|
|
56
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagEndIndex).toEqual(36);
|
|
57
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagStartIndex).toEqual(47);
|
|
58
|
+
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* () {
|
|
61
|
+
const innerHTML = "<f-when value=\"{{show}}\">{{text}}</f-when>";
|
|
62
|
+
const templateResult = getNextBehavior(innerHTML);
|
|
63
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.type).toEqual("templateDirective");
|
|
64
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagStartIndex).toEqual(0);
|
|
65
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.openingTagEndIndex).toEqual(25);
|
|
66
|
+
expect(templateResult === null || templateResult === void 0 ? void 0 : templateResult.closingTagStartIndex).toEqual(33);
|
|
67
|
+
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>";
|
|
73
|
+
const result = getNextBehavior(innerHTML);
|
|
74
|
+
expect(result === null || result === void 0 ? void 0 : result.type).toEqual("dataBinding");
|
|
75
|
+
expect(result === null || result === void 0 ? void 0 : result.subtype).toEqual("attributeDirective");
|
|
76
|
+
expect(result === null || result === void 0 ? void 0 : result.name).toEqual("children");
|
|
77
|
+
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>";
|
|
84
|
+
const result = getNextBehavior(innerHTML);
|
|
85
|
+
expect(result === null || result === void 0 ? void 0 : result.type).toEqual("dataBinding");
|
|
86
|
+
expect(result === null || result === void 0 ? void 0 : result.subtype).toEqual("attributeDirective");
|
|
87
|
+
expect(result === null || result === void 0 ? void 0 : result.name).toEqual("slotted");
|
|
88
|
+
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>";
|
|
95
|
+
const result = getNextBehavior(innerHTML);
|
|
96
|
+
expect(result === null || result === void 0 ? void 0 : result.type).toEqual("dataBinding");
|
|
97
|
+
expect(result === null || result === void 0 ? void 0 : result.subtype).toEqual("attributeDirective");
|
|
98
|
+
expect(result === null || result === void 0 ? void 0 : result.name).toEqual("ref");
|
|
99
|
+
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* () {
|
|
130
|
+
const index = getIndexOfNextMatchingTag(`<div>Hello world</div>`, `<div`, `</div>`, 0);
|
|
131
|
+
expect(index).toEqual(16);
|
|
132
|
+
}));
|
|
133
|
+
test("should resolve when there is a nested tag", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
const index = getIndexOfNextMatchingTag(`<div><div>Hello world</div></div>`, `<div`, `</div>`, 0);
|
|
135
|
+
expect(index).toEqual(27);
|
|
136
|
+
}));
|
|
137
|
+
test("should get adjacent tags", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
138
|
+
const index = getIndexOfNextMatchingTag(`<div>Hello world</div><div>Hello pluto</div>`, `<div`, `</div>`, 0);
|
|
139
|
+
expect(index).toEqual(16);
|
|
140
|
+
}));
|
|
141
|
+
test("should add an offset for content before the tag", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
142
|
+
const index = getIndexOfNextMatchingTag(`<div>Hello world</div>`, `<div`, `</div>`, 23);
|
|
143
|
+
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
|
+
}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create a non-binding attribute", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/attribute");
|
|
6
|
+
const customElement = page.locator("test-element");
|
|
7
|
+
const customElementInput = customElement.locator("input");
|
|
8
|
+
yield expect(customElementInput).toHaveAttribute("disabled");
|
|
9
|
+
}));
|
|
10
|
+
test("create an attribute binding", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
11
|
+
yield page.goto("/attribute");
|
|
12
|
+
const customElement = page.locator("test-element");
|
|
13
|
+
yield expect(customElement).toHaveAttribute("type", "checkbox");
|
|
14
|
+
yield expect(customElement.locator("input[type='checkbox']")).toHaveCount(1);
|
|
15
|
+
yield page.evaluate(() => {
|
|
16
|
+
var _a;
|
|
17
|
+
const customElement = document.getElementsByTagName("test-element");
|
|
18
|
+
(_a = customElement.item(0)) === null || _a === void 0 ? void 0 : _a.setAttribute("type", "radio");
|
|
19
|
+
});
|
|
20
|
+
yield expect(customElement).toHaveAttribute("type", "radio");
|
|
21
|
+
yield expect(customElement.locator("input[type='radio']")).toHaveCount(1);
|
|
22
|
+
}));
|
|
23
|
+
}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { TemplateElement } from "@microsoft/fast-html";
|
|
3
|
+
import { attr, FASTElement } from "@microsoft/fast-element";
|
|
4
|
+
class TestElement extends FASTElement {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.type = "radio";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
__decorate([
|
|
11
|
+
attr,
|
|
12
|
+
__metadata("design:type", String)
|
|
13
|
+
], TestElement.prototype, "type", void 0);
|
|
14
|
+
TestElement.define({
|
|
15
|
+
name: "test-element",
|
|
16
|
+
});
|
|
17
|
+
TemplateElement.define({
|
|
18
|
+
name: "f-template",
|
|
19
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create a binding", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/binding");
|
|
6
|
+
const customElement = yield page.locator("test-element");
|
|
7
|
+
yield expect(yield customElement.getAttribute("text")).toEqual("Hello world");
|
|
8
|
+
yield expect(customElement).toHaveText("Hello world");
|
|
9
|
+
yield page.evaluate(() => {
|
|
10
|
+
var _a;
|
|
11
|
+
const customElement = document.getElementsByTagName("test-element");
|
|
12
|
+
(_a = customElement.item(0)) === null || _a === void 0 ? void 0 : _a.setAttribute("text", "Hello pluto");
|
|
13
|
+
});
|
|
14
|
+
yield expect(yield customElement.getAttribute("text")).toEqual("Hello pluto");
|
|
15
|
+
yield expect(customElement).toHaveText("Hello pluto");
|
|
16
|
+
}));
|
|
17
|
+
}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { TemplateElement } from "@microsoft/fast-html";
|
|
3
|
+
import { attr, FASTElement } from "@microsoft/fast-element";
|
|
4
|
+
class TestElement extends FASTElement {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.text = "Hello";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
__decorate([
|
|
11
|
+
attr,
|
|
12
|
+
__metadata("design:type", String)
|
|
13
|
+
], TestElement.prototype, "text", void 0);
|
|
14
|
+
TestElement.define({
|
|
15
|
+
name: "test-element",
|
|
16
|
+
});
|
|
17
|
+
TemplateElement.define({
|
|
18
|
+
name: "f-template",
|
|
19
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create a children directive", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/children");
|
|
6
|
+
const listItemCount1 = yield page.evaluate(() => {
|
|
7
|
+
var _a;
|
|
8
|
+
const customElement = document.getElementsByTagName("test-element");
|
|
9
|
+
const listItems = (_a = customElement.item(0)) === null || _a === void 0 ? void 0 : _a.listItems.filter((listItem) => {
|
|
10
|
+
return listItem instanceof HTMLLIElement;
|
|
11
|
+
});
|
|
12
|
+
return listItems === null || listItems === void 0 ? void 0 : listItems.length;
|
|
13
|
+
});
|
|
14
|
+
expect(listItemCount1).toEqual(2);
|
|
15
|
+
yield page.evaluate(() => {
|
|
16
|
+
const customElement = document.getElementsByTagName("test-element");
|
|
17
|
+
customElement.item(0).list = [
|
|
18
|
+
"A",
|
|
19
|
+
"B",
|
|
20
|
+
"C"
|
|
21
|
+
];
|
|
22
|
+
});
|
|
23
|
+
const listItemCount2 = yield page.evaluate(() => {
|
|
24
|
+
var _a;
|
|
25
|
+
const customElement = document.getElementsByTagName("test-element");
|
|
26
|
+
const listItems = (_a = customElement.item(0)) === null || _a === void 0 ? void 0 : _a.listItems.filter((listItem) => {
|
|
27
|
+
return listItem instanceof HTMLLIElement;
|
|
28
|
+
});
|
|
29
|
+
return listItems === null || listItems === void 0 ? void 0 : listItems.length;
|
|
30
|
+
});
|
|
31
|
+
expect(listItemCount2).toEqual(3);
|
|
32
|
+
}));
|
|
33
|
+
}));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { TemplateElement } from "@microsoft/fast-html";
|
|
3
|
+
import { FASTElement, observable } from "@microsoft/fast-element";
|
|
4
|
+
class TestElement extends FASTElement {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.listItems = [];
|
|
8
|
+
this.list = ["Foo", "Bar"];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
__decorate([
|
|
12
|
+
observable,
|
|
13
|
+
__metadata("design:type", Array)
|
|
14
|
+
], TestElement.prototype, "listItems", void 0);
|
|
15
|
+
__decorate([
|
|
16
|
+
observable,
|
|
17
|
+
__metadata("design:type", Array)
|
|
18
|
+
], TestElement.prototype, "list", void 0);
|
|
19
|
+
TestElement.define({
|
|
20
|
+
name: "test-element",
|
|
21
|
+
});
|
|
22
|
+
TemplateElement.define({
|
|
23
|
+
name: "f-template",
|
|
24
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create a object property reference using dot syntax in a binding", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/dot-syntax");
|
|
6
|
+
const customElement = yield page.locator("test-element");
|
|
7
|
+
yield expect(customElement).toHaveText("bar");
|
|
8
|
+
}));
|
|
9
|
+
}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TemplateElement } from "@microsoft/fast-html";
|
|
2
|
+
import { FASTElement } from "@microsoft/fast-element";
|
|
3
|
+
class TestElement extends FASTElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.object = {
|
|
7
|
+
foo: "bar",
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
TestElement.define({
|
|
12
|
+
name: "test-element",
|
|
13
|
+
});
|
|
14
|
+
TemplateElement.define({
|
|
15
|
+
name: "f-template",
|
|
16
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create an event attribute", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/event");
|
|
6
|
+
const customElement = yield page.locator("test-element");
|
|
7
|
+
let msgCount = 0;
|
|
8
|
+
yield page.on("console", msg => msgCount++);
|
|
9
|
+
yield customElement.locator("button").click();
|
|
10
|
+
expect(msgCount).toEqual(1);
|
|
11
|
+
}));
|
|
12
|
+
}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TemplateElement } from "@microsoft/fast-html";
|
|
2
|
+
import { FASTElement } from "@microsoft/fast-element";
|
|
3
|
+
class TestElement extends FASTElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.handleClick = () => {
|
|
7
|
+
console.log("click!");
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
TestElement.define({
|
|
12
|
+
name: "test-element",
|
|
13
|
+
});
|
|
14
|
+
TemplateElement.define({
|
|
15
|
+
name: "f-template",
|
|
16
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { TemplateElement } from "@microsoft/fast-html";
|
|
2
|
+
import { FASTElement } from "@microsoft/fast-element";
|
|
3
|
+
class TestElement extends FASTElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.items = [
|
|
7
|
+
{
|
|
8
|
+
text: "Hello",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
text: "Earth",
|
|
12
|
+
items: [
|
|
13
|
+
{
|
|
14
|
+
text: "Pluto",
|
|
15
|
+
items: [
|
|
16
|
+
{
|
|
17
|
+
text: "Mars",
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
TestElement.define({
|
|
27
|
+
name: "test-element",
|
|
28
|
+
});
|
|
29
|
+
TemplateElement.define({
|
|
30
|
+
name: "f-template",
|
|
31
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create a partial", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/partial");
|
|
6
|
+
const customElement = yield page.locator("#test");
|
|
7
|
+
let customElementListItems = yield customElement.locator("li");
|
|
8
|
+
expect(yield customElementListItems.count()).toEqual(4);
|
|
9
|
+
expect(yield customElementListItems.nth(0).textContent()).toEqual("Hello");
|
|
10
|
+
expect(yield customElementListItems.nth(1).textContent()).toContain("Earth");
|
|
11
|
+
expect(yield customElementListItems.nth(2).textContent()).toContain("Pluto");
|
|
12
|
+
expect(yield customElementListItems.nth(3).textContent()).toContain("Mars");
|
|
13
|
+
}));
|
|
14
|
+
}));
|