diff options
author | 2022-03-07 15:36:22 -0600 | |
---|---|---|
committer | 2022-03-07 15:36:22 -0600 | |
commit | f18ee36dc0abdc5c8ec87734de7962966d16fe65 (patch) | |
tree | c01a7034186cb0bbe5e1d042f4a5dd09bad21ed5 /packages/webapi/src/lib/Document.ts | |
parent | 10a9c3412b4f6e8607687a74eafdb150d3222047 (diff) | |
download | astro-f18ee36dc0abdc5c8ec87734de7962966d16fe65.tar.gz astro-f18ee36dc0abdc5c8ec87734de7962966d16fe65.tar.zst astro-f18ee36dc0abdc5c8ec87734de7962966d16fe65.zip |
Add `@astrojs/webapi` package (#2729)@astrojs/webapi@0.11.0
* chore: add @astrojs/webapi
* chore: update package.json
* fix: update file case
* fix: remove lowercase file
* chore: update tests to use mocha
* chore: update LICENSE
Diffstat (limited to 'packages/webapi/src/lib/Document.ts')
-rw-r--r-- | packages/webapi/src/lib/Document.ts | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/packages/webapi/src/lib/Document.ts b/packages/webapi/src/lib/Document.ts new file mode 100644 index 000000000..867cc4448 --- /dev/null +++ b/packages/webapi/src/lib/Document.ts @@ -0,0 +1,159 @@ +import * as _ from './utils' +import { Text } from './CharacterData' +import { TreeWalker } from './TreeWalker' + +export class Document extends Node { + createElement(name: string) { + const internals = _.internalsOf<DocumentInternals>(this, 'Document', 'createElement') + + const customElementInternals: CustomElementRegistryInternals = _.INTERNALS.get(internals.target.customElements) + + name = String(name).toLowerCase() + + const TypeOfHTMLElement = internals.constructorByName.get(name) || (customElementInternals && customElementInternals.constructorByName.get(name)) || HTMLUnknownElement + + const element = Object.setPrototypeOf(new EventTarget(), TypeOfHTMLElement.prototype) as HTMLElement + + _.INTERNALS.set(element, { + attributes: {}, + localName: name, + ownerDocument: this, + shadowInit: null as unknown as ShadowRootInit, + shadowRoot: null as unknown as ShadowRoot, + } as ElementInternals) + + return element + } + + createNodeIterator(root: Node, whatToShow: number = NodeFilter.SHOW_ALL, filter?: NodeIteratorInternals['filter']) { + const target = Object.create(NodeIterator.prototype) + + _.INTERNALS.set(target, { filter, pointerBeforeReferenceNode: false, referenceNode: root, root, whatToShow } as NodeIteratorInternals) + + return target + } + + createTextNode(data: string) { + return new Text(data) + } + + createTreeWalker(root: Node, whatToShow: number = NodeFilter.SHOW_ALL, filter?: NodeFilter, expandEntityReferences?: boolean) { + const target = Object.create(TreeWalker.prototype) + + _.INTERNALS.set(target, { filter, currentNode: root, root, whatToShow } as TreeWalkerInternals) + + return target + } + + get adoptedStyleSheets(): StyleSheet[] { + return [] + } + + get styleSheets(): StyleSheet[] { + return [] + } + + body!: HTMLBodyElement + documentElement!: HTMLHtmlElement + head!: HTMLHeadElement +} + +export class HTMLDocument extends Document {} + +_.allowStringTag(Document) +_.allowStringTag(HTMLDocument) + +export const initDocument = (target: Target, exclude: Set<string>) => { + if (exclude.has('document')) return + + const EventTarget = target.EventTarget || globalThis.EventTarget + const HTMLDocument = target.HTMLDocument || globalThis.HTMLDocument + + const document: HTMLDocument = target.document = Object.setPrototypeOf(new EventTarget(), HTMLDocument.prototype) + + _.INTERNALS.set(document, { + target, + constructorByName: new Map<string, Function>([ + ['body', target.HTMLBodyElement], + ['canvas', target.HTMLCanvasElement], + ['div', target.HTMLDivElement], + ['head', target.HTMLHeadElement], + ['html', target.HTMLHtmlElement], + ['img', target.HTMLImageElement], + ['span', target.HTMLSpanElement], + ['style', target.HTMLStyleElement], + ]), + nameByConstructor: new Map, + } as DocumentInternals) + + const initElement = (name: string, Class: Function) => { + const target = Object.setPrototypeOf(new EventTarget(), Class.prototype) + + _.INTERNALS.set(target, { + attributes: {}, + localName: name, + ownerDocument: document, + shadowRoot: null as unknown as ShadowRoot, + shadowInit: null as unknown as ShadowRootInit, + } as ElementInternals) + + return target + } + + document.body = initElement('body', target.HTMLBodyElement) as HTMLBodyElement + document.head = initElement('head', target.HTMLHeadElement) as HTMLHeadElement + document.documentElement = initElement('html', target.HTMLHtmlElement) as HTMLHtmlElement +} + +interface DocumentInternals { + body: HTMLBodyElement + documentElement: HTMLHtmlElement + head: HTMLHeadElement + constructorByName: Map<string, Function> + nameByConstructor: Map<Function, string> + target: Target +} + +interface CustomElementRegistryInternals { + constructorByName: Map<string, Function> + nameByConstructor: Map<Function, string> +} + +interface ElementInternals { + attributes: { [name: string]: string }, + localName: string + ownerDocument: Document + shadowRoot: ShadowRoot + shadowInit: ShadowRootInit +} + +interface ShadowRootInit extends Record<any, any> { + mode?: string +} + +interface Target extends Record<any, any> { + HTMLBodyElement: typeof HTMLBodyElement + HTMLDivElement: typeof HTMLDivElement + HTMLElement: typeof HTMLElement + HTMLHeadElement: typeof HTMLHeadElement + HTMLHtmlElement: typeof HTMLHtmlElement + HTMLSpanElement: typeof HTMLSpanElement + HTMLStyleElement: typeof HTMLStyleElement + customElements: CustomElementRegistry + document: DocumentInternals +} + +interface NodeIteratorInternals { + filter: NodeFilter + pointerBeforeReferenceNode: boolean + referenceNode: Node + root: Node + whatToShow: number +} + +interface TreeWalkerInternals { + filter: NodeFilter + currentNode: Node + root: Node + whatToShow: number +} |