Skip to content

Commit

Permalink
refactor: extract polyfill and polyfill-like code to an optional modu…
Browse files Browse the repository at this point in the history
…le (#5752)

* refactor: extract polyfill and polyfill-like code to an optional module

* Change files

* fix: correct build break in fast-foundation from removing $global

* fix: update templates to use classList and fix classList bug

* Change files

* feat: require trusted types for bindings to innerHtml & move core policy

* fix: bug that arises when there are real trusted types

* refactor: minor internal cleanup in the polyfills

* fix: remove polyfill external module dependency

Co-authored-by: EisenbergEffect <[email protected]>
  • Loading branch information
EisenbergEffect and EisenbergEffect authored Mar 17, 2022
1 parent 1537dd9 commit 56dee75
Show file tree
Hide file tree
Showing 23 changed files with 382 additions and 339 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "refactor: extract polyfill and polyfill-like code to an optional module",
"packageName": "@microsoft/fast-element",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: update templates to use classList and fix classList bug",
"packageName": "@microsoft/fast-foundation",
"email": "[email protected]",
"dependentChangeType": "patch"
}
80 changes: 51 additions & 29 deletions packages/web-components/fast-element/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,38 @@
```ts

// @public
export const $global: Global;

// @public
export interface Accessor {
getValue(source: any): any;
name: string;
setValue(source: any, value: any): void;
}

// Warning: (ae-internal-missing-underscore) The name "AdoptedStyleSheetsStrategy" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export class AdoptedStyleSheetsStrategy implements StyleStrategy {
constructor(styles: (string | CSSStyleSheet)[]);
// (undocumented)
addStylesTo(target: StyleTarget): void;
// (undocumented)
removeStylesFrom(target: StyleTarget): void;
// (undocumented)
readonly sheets: CSSStyleSheet[];
}

// @public
export enum Aspect {
attribute = 0,
booleanAttribute = 1,
content = 3,
event = 5,
property = 2,
tokenList = 4
}

// @public
export abstract class AspectedHTMLDirective extends HTMLDirective {
// Warning: (ae-forgotten-export) The symbol "Aspect" needs to be exported by the entry point index.d.ts
abstract readonly aspect: Aspect;
abstract readonly binding?: Binding;
abstract captureSource(source: string): void;
Expand Down Expand Up @@ -117,7 +136,7 @@ export interface ChildListDirectiveOptions<T = any> extends NodeBehaviorOptions<
// @public
export function children<T = any>(propertyOrOptions: (keyof T & string) | ChildListDirectiveOptions<keyof T & string>): CaptureType<T>;

// Warning: (ae-forgotten-export) The symbol "NodeObservationDirective" needs to be exported by the entry point index.d.ts
// Warning: (ae-incompatible-release-tags) The symbol "ChildrenDirective" is marked as @public, but its signature references "NodeObservationDirective" which is marked as @internal
//
// @public
export class ChildrenDirective extends NodeObservationDirective<ChildrenDirectiveOptions> {
Expand All @@ -137,6 +156,7 @@ directives: readonly HTMLDirective[]) => HTMLTemplateCompilationResult;

// @public
export const Compiler: {
setHTMLPolicy(policy: TrustedTypesPolicy): void;
compile(html: string | HTMLTemplateElement, directives: ReadonlyArray<HTMLDirective>): HTMLTemplateCompilationResult;
setDefaultStrategy(strategy: CompilationStrategy): void;
aggregate(parts: (string | HTMLDirective)[]): HTMLDirective;
Expand Down Expand Up @@ -207,8 +227,6 @@ export const defaultExecutionContext: ExecutionContext<any, any>;
// @public
export const DOM: Readonly<{
supportsAdoptedStyleSheets: boolean;
setHTMLPolicy(policy: TrustedTypesPolicy): void;
createHTML(html: string): string;
setUpdateMode: (isAsync: boolean) => void;
queueUpdate: (callable: Callable) => void;
nextUpdate(): Promise<void>;
Expand Down Expand Up @@ -328,12 +346,6 @@ export interface FASTGlobal {
readonly versions: string[];
}

// @public
export type Global = typeof globalThis & {
trustedTypes: TrustedTypes;
readonly FAST: FASTGlobal;
};

// @public
export function html<TSource = any, TParent = any, TGrandparent = any>(strings: TemplateStringsArray, ...values: TemplateValue<TSource, TParent>[]): ViewTemplate<TSource, TParent, TGrandparent>;

Expand Down Expand Up @@ -366,20 +378,6 @@ export class HTMLView<TSource = any, TParent = any, TGrandparent = any> implemen
unbind(): void;
}

// Warning: (ae-internal-missing-underscore) The name "KernelServiceId" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export const enum KernelServiceId {
// (undocumented)
contextEvent = 3,
// (undocumented)
elementRegistry = 4,
// (undocumented)
observable = 2,
// (undocumented)
updateQueue = 1
}

// @public
export const Markup: Readonly<{
interpolation: (index: number) => string;
Expand All @@ -400,6 +398,19 @@ export interface NodeBehaviorOptions<T = any> {
property: T;
}

// Warning: (ae-internal-missing-underscore) The name "NodeObservationDirective" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export abstract class NodeObservationDirective<T extends NodeBehaviorOptions> extends StatelessAttachedAttributeDirective<T> {
bind(source: any, context: ExecutionContext<any, any>, targets: ViewBehaviorTargets): void;
protected computeNodes(target: any): Node[];
protected abstract disconnect(target: any): void;
protected abstract getNodes(target: any): Node[];
protected abstract observe(target: any): void;
unbind(source: any, context: ExecutionContext<any, any>, targets: ViewBehaviorTargets): void;
protected updateTarget(source: any, value: ReadonlyArray<any>): void;
}

// @public
export interface Notifier {
notify(args: any): void;
Expand Down Expand Up @@ -468,8 +479,6 @@ export class PropertyChangeNotifier implements Notifier {
// @public
export const ref: <T = any>(propertyName: keyof T & string) => CaptureType<T>;

// Warning: (ae-forgotten-export) The symbol "StatelessAttachedAttributeDirective" needs to be exported by the entry point index.d.ts
//
// @public
export class RefDirective extends StatelessAttachedAttributeDirective<string> {
bind(source: any, context: ExecutionContext, targets: ViewBehaviorTargets): void;
Expand Down Expand Up @@ -504,6 +513,8 @@ export interface RepeatOptions {
// @public
export function slotted<T = any>(propertyOrOptions: (keyof T & string) | SlottedDirectiveOptions<keyof T & string>): CaptureType<T>;

// Warning: (ae-incompatible-release-tags) The symbol "SlottedDirective" is marked as @public, but its signature references "NodeObservationDirective" which is marked as @internal
//
// @public
export class SlottedDirective extends NodeObservationDirective<SlottedDirectiveOptions> {
disconnect(target: EventSource): void;
Expand All @@ -530,6 +541,17 @@ export class Splice {
removed: any[];
}

// @public
export abstract class StatelessAttachedAttributeDirective<T> extends HTMLDirective implements ViewBehavior {
constructor(options: T);
abstract bind(source: any, context: ExecutionContext, targets: ViewBehaviorTargets): void;
createBehavior(targets: ViewBehaviorTargets): ViewBehavior;
createPlaceholder: (index: number) => string;
// (undocumented)
protected options: T;
abstract unbind(source: any, context: ExecutionContext, targets: ViewBehaviorTargets): void;
}

// @public
export interface StyleStrategy {
addStylesTo(target: StyleTarget): void;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Mutable } from "../interfaces.js";
import type { Mutable, StyleTarget } from "../interfaces.js";
import type { Behavior } from "../observation/behavior.js";
import { PropertyChangeNotifier } from "../observation/notifier.js";
import { defaultExecutionContext, Observable } from "../observation/observable.js";
import type { ElementStyles, StyleTarget } from "../styles/element-styles.js";
import type { ElementStyles } from "../styles/element-styles.js";
import type { ElementViewTemplate } from "../templating/template.js";
import type { ElementView } from "../templating/view.js";
import { FASTElementDefinition } from "./fast-definitions.js";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isString } from "../interfaces.js";
import { isString, KernelServiceId } from "../interfaces.js";
import { Observable } from "../observation/observable.js";
import { FAST, KernelServiceId } from "../platform.js";
import { FAST } from "../platform.js";
import { ComposableStyles, ElementStyles } from "../styles/element-styles.js";
import type { ElementViewTemplate } from "../templating/template.js";
import { AttributeConfiguration, AttributeDefinition } from "./attributes.js";
Expand Down
45 changes: 4 additions & 41 deletions packages/web-components/fast-element/src/dom.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import type { Callable } from "./interfaces.js";
import { $global, KernelServiceId, TrustedTypesPolicy } from "./platform.js";

/* eslint-disable */
const fastHTMLPolicy: TrustedTypesPolicy = $global.trustedTypes.createPolicy(
"fast-html",
{
createHTML: html => html,
}
);
/* eslint-enable */
import { Callable, KernelServiceId } from "./interfaces.js";
import { FAST } from "./platform.js";

const updateQueue = $global.FAST.getById(KernelServiceId.updateQueue, () => {
const updateQueue = FAST.getById(KernelServiceId.updateQueue, () => {
const tasks: Callable[] = [];
const pendingErrors: any[] = [];
const rAF = $global.requestAnimationFrame;
const rAF = globalThis.requestAnimationFrame;
let updateAsync = true;

function throwFirstError(): void {
Expand Down Expand Up @@ -85,8 +76,6 @@ const updateQueue = $global.FAST.getById(KernelServiceId.updateQueue, () => {
});
});

let htmlPolicy: TrustedTypesPolicy = fastHTMLPolicy;

/**
* Common DOM APIs.
* @public
Expand All @@ -99,32 +88,6 @@ export const DOM = Object.freeze({
Array.isArray((document as any).adoptedStyleSheets) &&
"replace" in CSSStyleSheet.prototype,

/**
* Sets the HTML trusted types policy used by the templating engine.
* @param policy - The policy to set for HTML.
* @remarks
* This API can only be called once, for security reasons. It should be
* called by the application developer at the start of their program.
*/
setHTMLPolicy(policy: TrustedTypesPolicy) {
if (htmlPolicy !== fastHTMLPolicy) {
throw new Error("The HTML policy can only be set once.");
}

htmlPolicy = policy;
},

/**
* Turns a string into trusted HTML using the configured trusted types policy.
* @param html - The string to turn into trusted HTML.
* @remarks
* Used internally by the template engine when creating templates
* and setting innerHTML.
*/
createHTML(html: string): string {
return htmlPolicy.createHTML(html);
},

/**
* Sets the update mode used by queueUpdate.
* @param isAsync - Indicates whether DOM updates should be asynchronous.
Expand Down
46 changes: 18 additions & 28 deletions packages/web-components/fast-element/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
export * from "./platform.js";
export * from "./templating/template.js";
export * from "./components/fast-element.js";
export {
FASTElementDefinition,
PartialFASTElementDefinition,
} from "./components/fast-definitions.js";
export * from "./components/fast-definitions.js";
export * from "./components/attributes.js";
export * from "./components/controller.js";
export type { Callable, Constructable, Mutable } from "./interfaces.js";
export * from "./templating/compiler.js";
export {
ElementStyles,
export type {
Callable,
Constructable,
FASTGlobal,
Mutable,
StyleStrategy,
ConstructibleStyleStrategy,
ComposableStyles,
StyleTarget,
} from "./styles/element-styles.js";
export { css, cssPartial } from "./styles/css.js";
export { CSSDirective } from "./styles/css-directive.js";
TrustedTypes,
TrustedTypesPolicy,
} from "./interfaces.js";
export * from "./templating/compiler.js";
export * from "./styles/element-styles.js";
export * from "./styles/css.js";
export * from "./styles/css-directive.js";
export * from "./observation/observable.js";
export * from "./observation/notifier.js";
export { Splice } from "./observation/array-change-records.js";
export { enableArrayObservation } from "./observation/array-observer.js";
export { DOM } from "./dom.js";
export * from "./observation/array-change-records.js";
export * from "./observation/array-observer.js";
export * from "./dom.js";
export type { Behavior } from "./observation/behavior.js";
export { Markup, Parser } from "./templating/markup.js";
export {
Expand All @@ -35,21 +35,11 @@ export {
BindingBehaviorFactory,
DefaultBindingOptions,
} from "./templating/binding.js";
export {
ViewBehaviorTargets,
ViewBehavior,
ViewBehaviorFactory,
HTMLDirective,
AspectedHTMLDirective,
} from "./templating/html-directive.js";
export * from "./templating/html-directive.js";
export * from "./templating/ref.js";
export * from "./templating/when.js";
export * from "./templating/repeat.js";
export * from "./templating/slotted.js";
export * from "./templating/children.js";
export * from "./templating/view.js";
export {
elements,
ElementsFilter,
NodeBehaviorOptions,
} from "./templating/node-observation.js";
export * from "./templating/node-observation.js";
Loading

0 comments on commit 56dee75

Please sign in to comment.