@microsoft/fast-element 2.0.0-beta.9 → 2.0.1

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 (142) hide show
  1. package/.eslintrc.json +1 -1
  2. package/CHANGELOG.json +518 -0
  3. package/CHANGELOG.md +181 -1
  4. package/README.md +1 -9
  5. package/api-extractor.context.json +14 -0
  6. package/api-extractor.di.json +14 -0
  7. package/dist/context/context.api.json +1068 -0
  8. package/dist/di/di.api.json +4929 -0
  9. package/dist/dts/binding/binding.d.ts +49 -0
  10. package/dist/dts/binding/normalize.d.ts +9 -0
  11. package/dist/dts/binding/one-time.d.ts +11 -0
  12. package/dist/dts/binding/one-way.d.ts +20 -0
  13. package/dist/dts/{templating/binding-signal.d.ts → binding/signal.d.ts} +19 -4
  14. package/dist/dts/{templating/binding-two-way.d.ts → binding/two-way.d.ts} +9 -5
  15. package/dist/dts/components/attributes.d.ts +7 -1
  16. package/dist/dts/components/element-controller.d.ts +104 -8
  17. package/dist/dts/components/element-hydration.d.ts +2 -0
  18. package/dist/dts/components/fast-definitions.d.ts +6 -0
  19. package/dist/dts/components/hydration.d.ts +56 -0
  20. package/dist/dts/components/install-hydration.d.ts +1 -0
  21. package/dist/dts/context.d.ts +29 -15
  22. package/dist/dts/di/di.d.ts +0 -5
  23. package/dist/dts/dom-policy.d.ts +83 -0
  24. package/dist/dts/dom.d.ts +100 -0
  25. package/dist/dts/hydration/target-builder.d.ts +63 -0
  26. package/dist/dts/index.d.ts +33 -26
  27. package/dist/dts/index.rollup.d.ts +0 -1
  28. package/dist/dts/index.rollup.debug.d.ts +0 -1
  29. package/dist/dts/interfaces.d.ts +32 -82
  30. package/dist/dts/metadata.d.ts +6 -5
  31. package/dist/dts/observation/arrays.d.ts +1 -1
  32. package/dist/dts/observation/observable.bench.d.ts +18 -0
  33. package/dist/dts/observation/observable.d.ts +5 -5
  34. package/dist/dts/pending-task.d.ts +19 -7
  35. package/dist/dts/platform.d.ts +11 -2
  36. package/dist/dts/polyfills.d.ts +0 -8
  37. package/dist/dts/styles/css-binding-directive.d.ts +60 -0
  38. package/dist/dts/styles/css.d.ts +9 -7
  39. package/dist/dts/styles/element-styles.d.ts +1 -14
  40. package/dist/dts/styles/host.d.ts +2 -5
  41. package/dist/dts/styles/style-strategy.d.ts +42 -0
  42. package/dist/dts/templating/compiler.d.ts +11 -13
  43. package/dist/dts/templating/{binding.d.ts → html-binding-directive.d.ts} +21 -41
  44. package/dist/dts/templating/html-directive.d.ts +44 -140
  45. package/dist/dts/templating/install-hydratable-view-templates.d.ts +1 -0
  46. package/dist/dts/templating/node-observation.d.ts +11 -1
  47. package/dist/dts/templating/ref.d.ts +4 -0
  48. package/dist/dts/templating/render.bench.d.ts +3 -0
  49. package/dist/dts/templating/render.d.ts +49 -9
  50. package/dist/dts/templating/repeat-basic-reverse.bench.d.ts +3 -0
  51. package/dist/dts/templating/repeat-basic-shift.bench.d.ts +3 -0
  52. package/dist/dts/templating/repeat.d.ts +31 -9
  53. package/dist/dts/templating/template.d.ts +97 -12
  54. package/dist/dts/templating/view.d.ts +146 -29
  55. package/dist/dts/templating/when-basic.bench.d.ts +3 -0
  56. package/dist/dts/templating/when-conditional.bench.d.ts +3 -0
  57. package/dist/dts/templating/when-switch.bench.d.ts +3 -0
  58. package/dist/dts/templating/when.d.ts +3 -1
  59. package/dist/dts/testing/fakes.d.ts +12 -1
  60. package/dist/dts/tsdoc-metadata.json +1 -1
  61. package/dist/dts/utilities.d.ts +55 -1
  62. package/dist/esm/binding/binding.js +18 -0
  63. package/dist/esm/binding/normalize.js +17 -0
  64. package/dist/esm/binding/one-time.js +21 -0
  65. package/dist/esm/binding/one-way.js +30 -0
  66. package/dist/esm/{templating/binding-signal.js → binding/signal.js} +22 -6
  67. package/dist/esm/{templating/binding-two-way.js → binding/two-way.js} +18 -12
  68. package/dist/esm/components/attributes.js +19 -6
  69. package/dist/esm/components/element-controller.js +319 -49
  70. package/dist/esm/components/element-hydration.js +2 -0
  71. package/dist/esm/components/fast-definitions.js +12 -4
  72. package/dist/esm/components/fast-element.js +3 -1
  73. package/dist/esm/components/hydration.js +104 -0
  74. package/dist/esm/components/install-hydration.js +3 -0
  75. package/dist/esm/context.js +26 -4
  76. package/dist/esm/debug.js +8 -2
  77. package/dist/esm/di/di.js +9 -12
  78. package/dist/esm/dom-policy.js +345 -0
  79. package/dist/esm/dom.js +101 -0
  80. package/dist/esm/hydration/target-builder.js +175 -0
  81. package/dist/esm/index.js +34 -25
  82. package/dist/esm/index.rollup.debug.js +3 -1
  83. package/dist/esm/index.rollup.js +3 -1
  84. package/dist/esm/interfaces.js +51 -3
  85. package/dist/esm/metadata.js +11 -8
  86. package/dist/esm/observation/arrays.js +1 -1
  87. package/dist/esm/observation/observable.bench.js +79 -0
  88. package/dist/esm/observation/observable.js +20 -15
  89. package/dist/esm/observation/update-queue.js +2 -2
  90. package/dist/esm/pending-task.js +13 -1
  91. package/dist/esm/platform.js +12 -2
  92. package/dist/esm/polyfills.js +3 -61
  93. package/dist/esm/styles/css-binding-directive.js +76 -0
  94. package/dist/esm/styles/css.js +14 -7
  95. package/dist/esm/styles/element-styles.js +0 -33
  96. package/dist/esm/styles/style-strategy.js +1 -0
  97. package/dist/esm/templating/children.js +8 -4
  98. package/dist/esm/templating/compiler.js +37 -44
  99. package/dist/esm/templating/html-binding-directive.js +218 -0
  100. package/dist/esm/templating/html-directive.js +25 -152
  101. package/dist/esm/templating/install-hydratable-view-templates.js +17 -0
  102. package/dist/esm/templating/node-observation.js +14 -8
  103. package/dist/esm/templating/ref.js +1 -1
  104. package/dist/esm/templating/render.bench.js +56 -0
  105. package/dist/esm/templating/render.js +74 -30
  106. package/dist/esm/templating/repeat-basic-reverse.bench.js +43 -0
  107. package/dist/esm/templating/repeat-basic-shift.bench.js +43 -0
  108. package/dist/esm/templating/repeat.js +116 -17
  109. package/dist/esm/templating/template.js +135 -60
  110. package/dist/esm/templating/view.js +254 -34
  111. package/dist/esm/templating/when-basic.bench.js +36 -0
  112. package/dist/esm/templating/when-conditional.bench.js +39 -0
  113. package/dist/esm/templating/when-switch.bench.js +68 -0
  114. package/dist/esm/templating/when.js +12 -5
  115. package/dist/esm/testing/fakes.js +32 -1
  116. package/dist/esm/testing/fixture.js +1 -1
  117. package/dist/esm/utilities.js +97 -1
  118. package/dist/fast-element.api.json +9789 -5667
  119. package/dist/fast-element.d.ts +813 -2392
  120. package/dist/fast-element.debug.js +2788 -974
  121. package/dist/fast-element.debug.min.js +3 -1
  122. package/dist/fast-element.js +2641 -833
  123. package/dist/fast-element.min.js +3 -1
  124. package/dist/fast-element.untrimmed.d.ts +662 -314
  125. package/docs/{api-report.md → api-report.api.md} +238 -151
  126. package/docs/context/api-report.api.md +69 -0
  127. package/docs/di/api-report.api.md +315 -0
  128. package/karma.conf.cjs +2 -1
  129. package/package.json +59 -47
  130. package/scripts/run-api-extractor.js +51 -0
  131. package/scripts/run-benchmarks.js +46 -0
  132. package/tensile.config.js +12 -0
  133. package/dist/dts/templating/dom.d.ts +0 -41
  134. package/dist/esm/templating/binding.js +0 -282
  135. package/dist/esm/templating/dom.js +0 -49
  136. package/docs/guide/declaring-templates.md +0 -230
  137. package/docs/guide/defining-elements.md +0 -214
  138. package/docs/guide/leveraging-css.md +0 -253
  139. package/docs/guide/next-steps.md +0 -13
  140. package/docs/guide/observables-and-state.md +0 -213
  141. package/docs/guide/using-directives.md +0 -576
  142. package/docs/guide/working-with-shadow-dom.md +0 -296
@@ -0,0 +1,175 @@
1
+ import { HydrationMarkup } from "../components/hydration.js";
2
+ export class HydrationTargetElementError extends Error {
3
+ constructor(
4
+ /**
5
+ * The error message
6
+ */
7
+ message,
8
+ /**
9
+ * The Compiled View Behavior Factories that belong to the view.
10
+ */
11
+ factories,
12
+ /**
13
+ * The node to target factory.
14
+ */
15
+ node) {
16
+ super(message);
17
+ this.factories = factories;
18
+ this.node = node;
19
+ }
20
+ }
21
+ function isComment(node) {
22
+ return node.nodeType === Node.COMMENT_NODE;
23
+ }
24
+ function isText(node) {
25
+ return node.nodeType === Node.TEXT_NODE;
26
+ }
27
+ /**
28
+ * Returns a range object inclusive of all nodes including and between the
29
+ * provided first and last node.
30
+ * @param first - The first node
31
+ * @param last - This last node
32
+ * @returns
33
+ */
34
+ export function createRangeForNodes(first, last) {
35
+ const range = document.createRange();
36
+ range.setStart(first, 0);
37
+ // The lastIndex should be inclusive of the end of the lastChild. Obtain offset based
38
+ // on usageNotes: https://developer.mozilla.org/en-US/docs/Web/API/Range/setEnd#usage_notes
39
+ range.setEnd(last, isComment(last) || isText(last) ? last.data.length : last.childNodes.length);
40
+ return range;
41
+ }
42
+ function isShadowRoot(node) {
43
+ return node instanceof DocumentFragment && "mode" in node;
44
+ }
45
+ /**
46
+ * Maps {@link CompiledViewBehaviorFactory} ids to the corresponding node targets for the view.
47
+ * @param firstNode - The first node of the view.
48
+ * @param lastNode - The last node of the view.
49
+ * @param factories - The Compiled View Behavior Factories that belong to the view.
50
+ * @returns - A {@link ViewBehaviorTargets } object for the factories in the view.
51
+ */
52
+ export function buildViewBindingTargets(firstNode, lastNode, factories) {
53
+ const range = createRangeForNodes(firstNode, lastNode);
54
+ const treeRoot = range.commonAncestorContainer;
55
+ const walker = document.createTreeWalker(treeRoot, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_COMMENT + NodeFilter.SHOW_TEXT, {
56
+ acceptNode(node) {
57
+ return range.comparePoint(node, 0) === 0
58
+ ? NodeFilter.FILTER_ACCEPT
59
+ : NodeFilter.FILTER_REJECT;
60
+ },
61
+ });
62
+ const targets = {};
63
+ const boundaries = {};
64
+ let node = (walker.currentNode = firstNode);
65
+ while (node !== null) {
66
+ switch (node.nodeType) {
67
+ case Node.ELEMENT_NODE: {
68
+ targetElement(node, factories, targets);
69
+ break;
70
+ }
71
+ case Node.COMMENT_NODE: {
72
+ targetComment(node, walker, factories, targets, boundaries);
73
+ break;
74
+ }
75
+ }
76
+ node = walker.nextNode();
77
+ }
78
+ range.detach();
79
+ return { targets, boundaries };
80
+ }
81
+ function targetElement(node, factories, targets) {
82
+ // Check for attributes and map any factories.
83
+ const attrFactoryIds = HydrationMarkup.parseAttributeBinding(node);
84
+ if (attrFactoryIds !== null) {
85
+ for (const id of attrFactoryIds) {
86
+ if (!factories[id]) {
87
+ throw new HydrationTargetElementError(`HydrationView was unable to successfully target factory on ${node.nodeName} inside ${node.getRootNode().host.nodeName}. This likely indicates a template mismatch between SSR rendering and hydration.`, factories, node);
88
+ }
89
+ targetFactory(factories[id], node, targets);
90
+ }
91
+ node.removeAttribute(HydrationMarkup.attributeMarkerName);
92
+ }
93
+ }
94
+ function targetComment(node, walker, factories, targets, boundaries) {
95
+ if (HydrationMarkup.isElementBoundaryStartMarker(node)) {
96
+ skipToElementBoundaryEndMarker(node, walker);
97
+ return;
98
+ }
99
+ if (HydrationMarkup.isContentBindingStartMarker(node.data)) {
100
+ const parsed = HydrationMarkup.parseContentBindingStartMarker(node.data);
101
+ if (parsed === null) {
102
+ return;
103
+ }
104
+ const [index, id] = parsed;
105
+ const factory = factories[index];
106
+ const nodes = [];
107
+ let current = walker.nextSibling();
108
+ node.data = "";
109
+ const first = current;
110
+ // Search for the binding end marker that closes the binding.
111
+ while (current !== null) {
112
+ if (isComment(current)) {
113
+ const parsed = HydrationMarkup.parseContentBindingEndMarker(current.data);
114
+ if (parsed && parsed[1] === id) {
115
+ break;
116
+ }
117
+ }
118
+ nodes.push(current);
119
+ current = walker.nextSibling();
120
+ }
121
+ if (current === null) {
122
+ const root = node.getRootNode();
123
+ throw new Error(`Error hydrating Comment node inside "${isShadowRoot(root) ? root.host.nodeName : root.nodeName}".`);
124
+ }
125
+ current.data = "";
126
+ if (nodes.length === 1 && isText(nodes[0])) {
127
+ targetFactory(factory, nodes[0], targets);
128
+ }
129
+ else {
130
+ // If current === first, it means there is no content in
131
+ // the view. This happens when a `when` directive evaluates false,
132
+ // or whenever a content binding returns null or undefined.
133
+ // In that case, there will never be any content
134
+ // to hydrate and Binding can simply create a HTMLView
135
+ // whenever it needs to.
136
+ if (current !== first && current.previousSibling !== null) {
137
+ boundaries[factory.targetNodeId] = {
138
+ first,
139
+ last: current.previousSibling,
140
+ };
141
+ }
142
+ // Binding evaluates to null / undefined or a template.
143
+ // If binding revaluates to string, it will replace content in target
144
+ // So we always insert a text node to ensure that
145
+ // text content binding will be written to this text node instead of comment
146
+ const dummyTextNode = current.parentNode.insertBefore(document.createTextNode(""), current);
147
+ targetFactory(factory, dummyTextNode, targets);
148
+ }
149
+ }
150
+ }
151
+ /**
152
+ * Moves TreeWalker to element boundary end marker
153
+ * @param node - element boundary start marker node
154
+ * @param walker - tree walker
155
+ */
156
+ function skipToElementBoundaryEndMarker(node, walker) {
157
+ const id = HydrationMarkup.parseElementBoundaryStartMarker(node.data);
158
+ let current = walker.nextSibling();
159
+ while (current !== null) {
160
+ if (isComment(current)) {
161
+ const parsed = HydrationMarkup.parseElementBoundaryEndMarker(current.data);
162
+ if (parsed && parsed === id) {
163
+ break;
164
+ }
165
+ }
166
+ current = walker.nextSibling();
167
+ }
168
+ }
169
+ export function targetFactory(factory, node, targets) {
170
+ if (factory.targetNodeId === undefined) {
171
+ // Dev error, this shouldn't ever be thrown
172
+ throw new Error("Factory could not be target to the node");
173
+ }
174
+ targets[factory.targetNodeId] = node;
175
+ }
package/dist/esm/index.js CHANGED
@@ -1,30 +1,39 @@
1
- export * from "./platform.js";
1
+ export { FAST, emptyArray } from "./platform.js";
2
+ // DOM
3
+ export { DOMAspect, DOM } from "./dom.js";
2
4
  // Observation
3
- export * from "./observation/observable.js";
4
- export * from "./observation/notifier.js";
5
- export * from "./observation/arrays.js";
6
- export * from "./observation/update-queue.js";
5
+ export { ExecutionContext, Observable, observable, SourceLifetime, volatile, } from "./observation/observable.js";
6
+ export { PropertyChangeNotifier, SubscriberSet, } from "./observation/notifier.js";
7
+ export { ArrayObserver, lengthOf, Splice, SpliceStrategy, SpliceStrategySupport, } from "./observation/arrays.js";
8
+ export { Updates } from "./observation/update-queue.js";
9
+ // Binding
10
+ export { Binding } from "./binding/binding.js";
11
+ export { listener, oneWay } from "./binding/one-way.js";
12
+ export { oneTime } from "./binding/one-time.js";
13
+ export { normalizeBinding } from "./binding/normalize.js";
7
14
  // Styles
8
- export * from "./styles/element-styles.js";
9
- export * from "./styles/css.js";
10
- export * from "./styles/css-directive.js";
11
- export * from "./styles/host.js";
15
+ export { ElementStyles, } from "./styles/element-styles.js";
16
+ export { css } from "./styles/css.js";
17
+ export { cssDirective, CSSDirective, } from "./styles/css-directive.js";
18
+ export {} from "./styles/host.js";
19
+ export {} from "./styles/style-strategy.js";
20
+ export { CSSBindingDirective } from "./styles/css-binding-directive.js";
12
21
  // Templating
13
- export * from "./templating/dom.js";
14
- export * from "./templating/template.js";
15
- export * from "./templating/compiler.js";
22
+ export { html, InlineTemplateDirective, ViewTemplate, } from "./templating/template.js";
23
+ export { Compiler } from "./templating/compiler.js";
16
24
  export { Markup, Parser } from "./templating/markup.js";
17
- export * from "./templating/binding.js";
18
- export * from "./templating/html-directive.js";
19
- export * from "./templating/ref.js";
20
- export * from "./templating/when.js";
21
- export * from "./templating/repeat.js";
22
- export * from "./templating/slotted.js";
23
- export * from "./templating/children.js";
24
- export * from "./templating/view.js";
25
- export * from "./templating/node-observation.js";
25
+ export { HTMLBindingDirective, } from "./templating/html-binding-directive.js";
26
+ export { htmlDirective, HTMLDirective, StatelessAttachedAttributeDirective, } from "./templating/html-directive.js";
27
+ export { ref, RefDirective } from "./templating/ref.js";
28
+ export { when } from "./templating/when.js";
29
+ export { repeat, RepeatBehavior, RepeatDirective, } from "./templating/repeat.js";
30
+ export { slotted, SlottedDirective, } from "./templating/slotted.js";
31
+ export { children, ChildrenDirective, } from "./templating/children.js";
32
+ export { HTMLView, HydrationBindingError, } from "./templating/view.js";
33
+ export { elements, NodeObservationDirective, } from "./templating/node-observation.js";
34
+ export { render, RenderBehavior, RenderDirective } from "./templating/render.js";
26
35
  // Components
27
- export * from "./components/fast-element.js";
28
- export * from "./components/fast-definitions.js";
29
- export * from "./components/attributes.js";
30
- export * from "./components/element-controller.js";
36
+ export { customElement, FASTElement } from "./components/fast-element.js";
37
+ export { FASTElementDefinition, } from "./components/fast-definitions.js";
38
+ export { attr, AttributeConfiguration, AttributeDefinition, booleanConverter, nullableBooleanConverter, nullableNumberConverter, } from "./components/attributes.js";
39
+ export { ElementController, HydratableElementController, } from "./components/element-controller.js";
@@ -1,3 +1,5 @@
1
- import "./polyfills.js";
2
1
  import "./debug.js";
2
+ import { DOMPolicy } from "./dom-policy.js";
3
+ import { DOM } from "./dom.js";
3
4
  export * from "./index.js";
5
+ DOM.setPolicy(DOMPolicy.create());
@@ -1,2 +1,4 @@
1
- import "./polyfills.js";
1
+ import { DOMPolicy } from "./dom-policy.js";
2
+ import { DOM } from "./dom.js";
2
3
  export * from "./index.js";
4
+ DOM.setPolicy(DOMPolicy.create());
@@ -1,12 +1,60 @@
1
+ let kernelMode;
2
+ const kernelAttr = "fast-kernel";
3
+ try {
4
+ if (document.currentScript) {
5
+ kernelMode = document.currentScript.getAttribute(kernelAttr);
6
+ }
7
+ else {
8
+ const scripts = document.getElementsByTagName("script");
9
+ const currentScript = scripts[scripts.length - 1];
10
+ kernelMode = currentScript.getAttribute(kernelAttr);
11
+ }
12
+ }
13
+ catch (e) {
14
+ kernelMode = "isolate";
15
+ }
16
+ let KernelServiceId;
17
+ switch (kernelMode) {
18
+ case "share": // share the kernel across major versions
19
+ KernelServiceId = Object.freeze({
20
+ updateQueue: 1,
21
+ observable: 2,
22
+ contextEvent: 3,
23
+ elementRegistry: 4,
24
+ });
25
+ break;
26
+ case "share-v2": // only share the kernel with other v2 instances
27
+ KernelServiceId = Object.freeze({
28
+ updateQueue: 1.2,
29
+ observable: 2.2,
30
+ contextEvent: 3.2,
31
+ elementRegistry: 4.2,
32
+ });
33
+ break;
34
+ default:
35
+ // fully isolate the kernel from all other FAST instances
36
+ const postfix = `-${Math.random().toString(36).substring(2, 8)}`;
37
+ KernelServiceId = Object.freeze({
38
+ updateQueue: `1.2${postfix}`,
39
+ observable: `2.2${postfix}`,
40
+ contextEvent: `3.2${postfix}`,
41
+ elementRegistry: `4.2${postfix}`,
42
+ });
43
+ break;
44
+ }
45
+ export { KernelServiceId };
1
46
  /**
2
- * @internal
47
+ * Determines whether or not an object is a function.
48
+ * @public
3
49
  */
4
50
  export const isFunction = (object) => typeof object === "function";
5
51
  /**
6
- * @internal
52
+ * Determines whether or not an object is a string.
53
+ * @public
7
54
  */
8
55
  export const isString = (object) => typeof object === "string";
9
56
  /**
10
- * @internal
57
+ * A function which does nothing.
58
+ * @public
11
59
  */
12
60
  export const noop = () => void 0;
@@ -22,8 +22,11 @@ if (!("metadata" in Reflect)) {
22
22
  return void 0;
23
23
  };
24
24
  }
25
+ const annotationParamTypesKey = "annotation:paramtypes";
26
+ const designParamTypesKey = "design:paramtypes";
25
27
  /**
26
28
  * Provides basic metadata capabilities used by Context and Dependency Injection.
29
+ * @public
27
30
  */
28
31
  export const Metadata = Object.freeze({
29
32
  /**
@@ -31,29 +34,29 @@ export const Metadata = Object.freeze({
31
34
  * @param Type - The type to get the metadata for.
32
35
  * @returns The metadata array or a frozen empty array if no metadata is found.
33
36
  */
34
- getDesignParamTypes: Type => {
37
+ getDesignParamTypes: (Type) => {
35
38
  var _a;
36
- return (_a = Reflect.getOwnMetadata("design:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
39
+ return ((_a = Reflect.getOwnMetadata(designParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
37
40
  },
38
41
  /**
39
42
  * Gets the "annotation:paramtypes" metadata for the specified type.
40
43
  * @param Type - The type to get the metadata for.
41
44
  * @returns The metadata array or a frozen empty array if no metadata is found.
42
45
  */
43
- getAnnotationParamTypes: Type => {
46
+ getAnnotationParamTypes: (Type) => {
44
47
  var _a;
45
- return (_a = Reflect.getOwnMetadata("annotation:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
48
+ return ((_a = Reflect.getOwnMetadata(annotationParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
46
49
  },
47
50
  /**
48
- *
49
- * @param Type - Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
51
+ * Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
50
52
  * an empty, mutable metadata array is created and added.
51
- * @returns The metadata array.
53
+ * @param Type - The type to get or create the metadata for.
54
+ * @returns A mutable metadata array.
52
55
  */
53
56
  getOrCreateAnnotationParamTypes(Type) {
54
57
  let types = this.getAnnotationParamTypes(Type);
55
58
  if (types === emptyArray) {
56
- Reflect.defineMetadata("annotation:paramtypes", (types = []), Type);
59
+ Reflect.defineMetadata(annotationParamTypesKey, (types = []), Type);
57
60
  }
58
61
  return types;
59
62
  },
@@ -369,7 +369,7 @@ let defaultSpliceStrategy = Object.freeze({
369
369
  if (changes === void 0) {
370
370
  return emptyArray;
371
371
  }
372
- return changes.length > 1 ? project(current, changes) : changes;
372
+ return project(current, changes);
373
373
  }
374
374
  return resetSplices;
375
375
  },
@@ -0,0 +1,79 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { attr, FASTElement, Observable } from "../index.js";
11
+ import { _random, adjectives, nouns } from "../__test__/utilities.js";
12
+ export class TestObservable extends FASTElement {
13
+ constructor() {
14
+ super(...arguments);
15
+ this._greetMessage = "";
16
+ this._name = "";
17
+ this._exit = false;
18
+ }
19
+ connectedCallback() {
20
+ super.connectedCallback();
21
+ const first = this.firstName[0].toUpperCase() + this.firstName.slice(1);
22
+ const last = this.lastName[0].toUpperCase() + this.lastName.slice(1);
23
+ this.name = `${first} ${last}`;
24
+ this.greetMessage = `Welcome to FAST, ${this.name} !!`;
25
+ }
26
+ get greetMessage() {
27
+ Observable.track(this, "greetMessage");
28
+ return this._greetMessage;
29
+ }
30
+ set greetMessage(value) {
31
+ this._greetMessage = value;
32
+ Observable.notify(this, "greetMessage");
33
+ }
34
+ get name() {
35
+ Observable.track(this, "name");
36
+ return this._name;
37
+ }
38
+ set name(value) {
39
+ this._name = value;
40
+ Observable.notify(this, "name");
41
+ }
42
+ get exit() {
43
+ Observable.track(this, "exit");
44
+ return this._exit;
45
+ }
46
+ set exit(value) {
47
+ this._exit = value;
48
+ Observable.notify(this, "exit");
49
+ }
50
+ }
51
+ __decorate([
52
+ attr,
53
+ __metadata("design:type", String)
54
+ ], TestObservable.prototype, "firstName", void 0);
55
+ __decorate([
56
+ attr,
57
+ __metadata("design:type", String)
58
+ ], TestObservable.prototype, "lastName", void 0);
59
+ TestObservable.define({
60
+ name: "test-observable",
61
+ });
62
+ const itemRenderer = () => {
63
+ const testObservable = document.createElement("test-observable");
64
+ testObservable.setAttribute("firstname", adjectives[_random(adjectives.length)]);
65
+ testObservable.setAttribute("lastname", nouns[_random(nouns.length)]);
66
+ const notifier = Observable.getNotifier(testObservable);
67
+ const handler = {
68
+ handleChange(source, propertyName) {
69
+ if (propertyName === "greetMessage")
70
+ source._exit = true;
71
+ },
72
+ };
73
+ notifier.subscribe(handler, "greetMessage");
74
+ testObservable.greetMessage = `Goodbye ${testObservable.name}, see you next time!`;
75
+ notifier.unsubscribe(handler, "greetMessage");
76
+ return testObservable;
77
+ };
78
+ export default itemRenderer;
79
+ export { tests } from "@tensile-perf/web-components";
@@ -1,5 +1,5 @@
1
- import { isFunction, isString, } from "../interfaces.js";
2
- import { createMetadataLocator, FAST } from "../platform.js";
1
+ import { isFunction, isString, KernelServiceId, } from "../interfaces.js";
2
+ import { createMetadataLocator, FAST, makeSerializationNoop } from "../platform.js";
3
3
  import { Updates } from "./update-queue.js";
4
4
  import { PropertyChangeNotifier, SubscriberSet } from "./notifier.js";
5
5
  /**
@@ -21,9 +21,9 @@ export const SourceLifetime = Object.freeze({
21
21
  * Common Observable APIs.
22
22
  * @public
23
23
  */
24
- export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
24
+ export const Observable = FAST.getById(KernelServiceId.observable, () => {
25
25
  const queueUpdate = Updates.enqueue;
26
- const volatileRegex = /(:|&&|\|\||if)/;
26
+ const volatileRegex = /(:|&&|\|\||if|\?\.)/;
27
27
  const notifierLookup = new WeakMap();
28
28
  let watcher = void 0;
29
29
  let createArrayObserver = (array) => {
@@ -66,9 +66,9 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
66
66
  }
67
67
  }
68
68
  class ExpressionNotifierImplementation extends SubscriberSet {
69
- constructor(binding, initialSubscriber, isVolatileBinding = false) {
70
- super(binding, initialSubscriber);
71
- this.binding = binding;
69
+ constructor(expression, initialSubscriber, isVolatileBinding = false) {
70
+ super(expression, initialSubscriber);
71
+ this.expression = expression;
72
72
  this.isVolatileBinding = isVolatileBinding;
73
73
  this.needsRefresh = true;
74
74
  this.needsQueue = true;
@@ -108,13 +108,17 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
108
108
  this.needsRefresh = this.isVolatileBinding;
109
109
  let result;
110
110
  try {
111
- result = this.binding(source, context);
111
+ result = this.expression(source, context);
112
112
  }
113
113
  finally {
114
114
  watcher = previousWatcher;
115
115
  }
116
116
  return result;
117
117
  }
118
+ // backwards compat with v1 kernel
119
+ disconnect() {
120
+ this.dispose();
121
+ }
118
122
  dispose() {
119
123
  if (this.last !== null) {
120
124
  let current = this.first;
@@ -176,6 +180,7 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
176
180
  }
177
181
  }
178
182
  }
183
+ makeSerializationNoop(ExpressionNotifierImplementation);
179
184
  return Object.freeze({
180
185
  /**
181
186
  * @internal
@@ -243,20 +248,20 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
243
248
  /**
244
249
  * Creates a {@link ExpressionNotifier} that can watch the
245
250
  * provided {@link Expression} for changes.
246
- * @param binding - The binding to observe.
251
+ * @param expression - The binding to observe.
247
252
  * @param initialSubscriber - An initial subscriber to changes in the binding value.
248
253
  * @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
249
254
  */
250
- binding(binding, initialSubscriber, isVolatileBinding = this.isVolatileBinding(binding)) {
251
- return new ExpressionNotifierImplementation(binding, initialSubscriber, isVolatileBinding);
255
+ binding(expression, initialSubscriber, isVolatileBinding = this.isVolatileBinding(expression)) {
256
+ return new ExpressionNotifierImplementation(expression, initialSubscriber, isVolatileBinding);
252
257
  },
253
258
  /**
254
259
  * Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
255
260
  * on every evaluation of the value.
256
- * @param binding - The binding to inspect.
261
+ * @param expression - The binding to inspect.
257
262
  */
258
- isVolatileBinding(binding) {
259
- return volatileRegex.test(binding.toString());
263
+ isVolatileBinding(expression) {
264
+ return volatileRegex.test(expression.toString());
260
265
  },
261
266
  });
262
267
  });
@@ -284,7 +289,7 @@ export function volatile(target, name, descriptor) {
284
289
  },
285
290
  });
286
291
  }
287
- const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
292
+ const contextEvent = FAST.getById(KernelServiceId.contextEvent, () => {
288
293
  let current = null;
289
294
  return {
290
295
  get() {
@@ -1,10 +1,10 @@
1
- import "../interfaces.js";
1
+ import { KernelServiceId } from "../interfaces.js";
2
2
  import { FAST } from "../platform.js";
3
3
  /**
4
4
  * The default UpdateQueue.
5
5
  * @public
6
6
  */
7
- export const Updates = FAST.getById(1 /* KernelServiceId.updateQueue */, () => {
7
+ export const Updates = FAST.getById(KernelServiceId.updateQueue, () => {
8
8
  const tasks = [];
9
9
  const pendingErrors = [];
10
10
  const rAF = globalThis.requestAnimationFrame;
@@ -1,16 +1,28 @@
1
1
  /**
2
2
  * A concrete implementation of {@link PendingTask}
3
- * @beta
3
+ * @public
4
4
  */
5
5
  export class PendingTaskEvent extends Event {
6
+ /**
7
+ * Creates an instance of PendingTaskEvent.
8
+ * @param complete - A promise that resolves when the pending task is complete.
9
+ */
6
10
  constructor(complete) {
7
11
  super(PendingTaskEvent.type, { bubbles: true, composed: true });
8
12
  this.complete = complete;
9
13
  }
14
+ /**
15
+ * Determines whether a value is a PendingTaskEvent.
16
+ * @param value - The value to check.
17
+ * @returns True if the value is a PendingTaskEvent; false otherwise.
18
+ */
10
19
  static isPendingTask(value) {
11
20
  var _a;
12
21
  return (value.type === PendingTaskEvent.type &&
13
22
  typeof ((_a = value.complete) === null || _a === void 0 ? void 0 : _a.then) === "function");
14
23
  }
15
24
  }
25
+ /**
26
+ * The type of the pending task event.
27
+ */
16
28
  PendingTaskEvent.type = "pending-task";
@@ -1,4 +1,6 @@
1
- // ensure FAST global - duplicated in polyfills.ts and debug.ts
1
+ import { noop } from "./interfaces.js";
2
+ import "./polyfills.js";
3
+ // ensure FAST global - duplicated debug.ts
2
4
  const propConfig = {
3
5
  configurable: false,
4
6
  enumerable: false,
@@ -9,7 +11,7 @@ if (globalThis.FAST === void 0) {
9
11
  }
10
12
  /**
11
13
  * The FAST global.
12
- * @internal
14
+ * @public
13
15
  */
14
16
  export const FAST = globalThis.FAST;
15
17
  if (FAST.getById === void 0) {
@@ -85,3 +87,11 @@ export function createMetadataLocator() {
85
87
  return metadata;
86
88
  };
87
89
  }
90
+ /**
91
+ * Makes a type noop for JSON serialization.
92
+ * @param type - The type to make noop for JSON serialization.
93
+ * @internal
94
+ */
95
+ export function makeSerializationNoop(type) {
96
+ type.prototype.toJSON = noop;
97
+ }