buninu-browser 0.0.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/AGENTS.md +13 -0
- package/Architecture.md +601 -0
- package/LICENSE +21 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/BSD-3-Clause-Skia.txt +29 -0
- package/LICENSES/Bitstream-Vera.txt +44 -0
- package/LICENSES/CC-BY-4.0.txt +396 -0
- package/LICENSES/OFL-1.1.txt +91 -0
- package/LICENSES/README.md +9 -0
- package/LICENSES/acorn.txt +21 -0
- package/LICENSES/chromium.txt +27 -0
- package/LICENSES/dropflow.txt +19 -0
- package/LICENSES/emscripten.txt +102 -0
- package/LICENSES/freetype.txt +169 -0
- package/LICENSES/happy-dom.txt +22 -0
- package/LICENSES/harfbuzz.txt +42 -0
- package/LICENSES/icu.txt +512 -0
- package/LICENSES/libjpeg-ijg.txt +260 -0
- package/LICENSES/libjpeg-turbo.txt +147 -0
- package/LICENSES/libpng.txt +134 -0
- package/LICENSES/libwebp.txt +30 -0
- package/LICENSES/ses-aura.txt +16 -0
- package/LICENSES/ses-caja.txt +13 -0
- package/LICENSES/ses-corejs.txt +19 -0
- package/LICENSES/ses-v8.txt +9 -0
- package/LICENSES/ses.txt +201 -0
- package/LICENSES/termdom.txt +21 -0
- package/LICENSES/wasmpeg.txt +501 -0
- package/LICENSES/woff2.txt +19 -0
- package/LICENSES/wuffs.txt +211 -0
- package/LICENSES/zlib.txt +22 -0
- package/Linux +0 -0
- package/PORTING.md +825 -0
- package/README.md +283 -0
- package/THIRD_PARTY_NOTICES.md +224 -0
- package/bunfig.toml +2 -0
- package/buninu-browser.js +65 -0
- package/index.js +149 -0
- package/lib/cdp-server.js +1424 -0
- package/lib/cdp.js +203 -0
- package/lib/happy-dom/entities-adapter.js +51 -0
- package/lib/happy-dom/image-size-adapter.js +8 -0
- package/lib/happy-dom/mime-type-adapter.js +27 -0
- package/lib/happy-dom/parser.js +53 -0
- package/lib/happy-dom/websocket-adapter.js +62 -0
- package/lib/headless-shell.js +362 -0
- package/lib/input/hit-test.js +78 -0
- package/lib/layout/scroll-viewport.js +53 -0
- package/lib/layout/text-layout.js +2236 -0
- package/lib/log.js +85 -0
- package/lib/network/cookie-jar.js +178 -0
- package/lib/network/network-service.js +268 -0
- package/lib/network/resolver.js +97 -0
- package/lib/paint/display-list.js +359 -0
- package/lib/paint/frame.js +88 -0
- package/lib/paint/gradient.js +207 -0
- package/lib/render-tree/index.js +263 -0
- package/lib/render-tree/svg.js +210 -0
- package/lib/renderer/bindings.js +1291 -0
- package/lib/renderer/compositor.js +123 -0
- package/lib/renderer/flags.js +20 -0
- package/lib/renderer/host.js +503 -0
- package/lib/renderer/main.js +234 -0
- package/lib/renderer/module-transform.js +399 -0
- package/lib/renderer/page-realm.js +1471 -0
- package/lib/renderer/page-renderer.js +1691 -0
- package/lib/renderer/script-rewrite.js +232 -0
- package/lib/renderer/seccomp.js +215 -0
- package/lib/renderer/syscall-numbers.js +139 -0
- package/lib/style/computed-style.js +2053 -0
- package/package.json +39 -0
- package/patches/happy-dom/0001-use-bun-entity-adapter.patch +15 -0
- package/patches/happy-dom/0002-use-bun-platform-adapters.patch +69 -0
- package/patches/happy-dom/README.md +38 -0
- package/test/chromium-headless-shell +5 -0
- package/test/compositor.test.js +154 -0
- package/test/computed-style.test.js +434 -0
- package/test/display-list.test.js +128 -0
- package/test/entities-adapter.test.js +43 -0
- package/test/fixtures/fake-renderer.js +26 -0
- package/test/fixtures/seccomp-child.js +32 -0
- package/test/fixtures/video.mp4 +0 -0
- package/test/flex.test.js +150 -0
- package/test/gradient.test.js +56 -0
- package/test/grid.test.js +253 -0
- package/test/happy-dom-platform-adapters.test.js +18 -0
- package/test/headless-shell.test.js +318 -0
- package/test/hit-test.test.js +49 -0
- package/test/html-parser.test.js +40 -0
- package/test/index.test.js +29 -0
- package/test/log.test.js +40 -0
- package/test/mobile.test.js +85 -0
- package/test/network-service.test.js +214 -0
- package/test/page-scripts.test.js +552 -0
- package/test/poc-backend.js +189 -0
- package/test/poc-backend.test.js +154 -0
- package/test/positioning.test.js +112 -0
- package/test/render-tree.test.js +103 -0
- package/test/renderer-host.test.js +69 -0
- package/test/resolver.test.js +51 -0
- package/test/script-rewrite.test.js +31 -0
- package/test/scroll-viewport.test.js +25 -0
- package/test/seccomp.test.js +71 -0
- package/test/site-isolation.test.js +74 -0
- package/test/svg.test.js +61 -0
- package/test/text-layout.test.js +419 -0
- package/usr/README.md +20 -0
- package/usr/lib/canvaskit/LICENSE +29 -0
- package/usr/lib/canvaskit/canvaskit.js +264 -0
- package/usr/lib/canvaskit/canvaskit.wasm +0 -0
- package/usr/share/fonts/DejaVuSansMono-Bold.ttf +0 -0
- package/usr/share/fonts/DejaVuSansMono.ttf +0 -0
- package/usr/share/fonts/LICENSE-Apache-2.0.txt +202 -0
- package/usr/share/fonts/LICENSE-DejaVu.txt +44 -0
- package/usr/share/fonts/LICENSE-OFL-1.1.txt +91 -0
- package/usr/share/fonts/NotoColorEmoji.ttf +0 -0
- package/usr/share/fonts/NotoColorEmojiFlags.ttf +0 -0
- package/usr/share/fonts/NotoSansCJK-Regular.ttc +0 -0
- package/usr/share/fonts/NotoSansSymbols-Regular-Subsetted.ttf +0 -0
- package/usr/share/fonts/NotoSansSymbols-Regular-Subsetted2.ttf +0 -0
- package/usr/share/fonts/Roboto-Regular.ttf +0 -0
- package/usr/share/fonts/fonts.json +28 -0
- package/vendor/acorn/LICENSE +21 -0
- package/vendor/acorn/README.md +309 -0
- package/vendor/acorn/dist/acorn.mjs +6313 -0
- package/vendor/acorn/package.json +50 -0
- package/vendor/happy-dom/.editorconfig +8 -0
- package/vendor/happy-dom/.eslintignore +6 -0
- package/vendor/happy-dom/.eslintrc.cjs +188 -0
- package/vendor/happy-dom/.github/CODEOWNERS +2 -0
- package/vendor/happy-dom/.github/FUNDING.yml +1 -0
- package/vendor/happy-dom/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- package/vendor/happy-dom/.github/ISSUE_TEMPLATE/custom.md +10 -0
- package/vendor/happy-dom/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/vendor/happy-dom/.github/PULL_REQUEST_TEMPLATE.md +27 -0
- package/vendor/happy-dom/.github/workflows/auto-assign.yml +23 -0
- package/vendor/happy-dom/.github/workflows/pull_request.yml +53 -0
- package/vendor/happy-dom/.github/workflows/release.yml +143 -0
- package/vendor/happy-dom/.husky/pre-commit +1 -0
- package/vendor/happy-dom/.prettierignore +1 -0
- package/vendor/happy-dom/.prettierrc.cjs +6 -0
- package/vendor/happy-dom/.vscode/extensions.json +3 -0
- package/vendor/happy-dom/CODE_OF_CONDUCT.md +128 -0
- package/vendor/happy-dom/CONTRIBUTING.md +147 -0
- package/vendor/happy-dom/LICENSE +21 -0
- package/vendor/happy-dom/README.md +62 -0
- package/vendor/happy-dom/SECURITY.md +12 -0
- package/vendor/happy-dom/cspell.json +34 -0
- package/vendor/happy-dom/docs/happy-dom-logo.jpg +0 -0
- package/vendor/happy-dom/integration-test/.editorconfig +8 -0
- package/vendor/happy-dom/integration-test/LICENSE +21 -0
- package/vendor/happy-dom/integration-test/README.md +1 -0
- package/vendor/happy-dom/integration-test/package.json +24 -0
- package/vendor/happy-dom/package-lock.json +15520 -0
- package/vendor/happy-dom/package.json +55 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/LICENSE +21 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/README.md +60 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/package.json +52 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/register.js +2 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/src/GlobalRegistrator.ts +121 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/src/index.ts +3 -0
- package/vendor/happy-dom/packages/@happy-dom/global-registrator/tsconfig.json +30 -0
- package/vendor/happy-dom/packages/@happy-dom/jest-environment/LICENSE +21 -0
- package/vendor/happy-dom/packages/@happy-dom/jest-environment/README.md +71 -0
- package/vendor/happy-dom/packages/@happy-dom/jest-environment/package.json +93 -0
- package/vendor/happy-dom/packages/@happy-dom/jest-environment/src/index.ts +192 -0
- package/vendor/happy-dom/packages/@happy-dom/jest-environment/tsconfig.json +30 -0
- package/vendor/happy-dom/packages/@happy-dom/node-canvas-adapter/README.md +48 -0
- package/vendor/happy-dom/packages/@happy-dom/node-canvas-adapter/package.json +41 -0
- package/vendor/happy-dom/packages/@happy-dom/node-canvas-adapter/src/CanvasAdapter.ts +275 -0
- package/vendor/happy-dom/packages/@happy-dom/node-canvas-adapter/src/index.ts +1 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/LICENSE +21 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/README.md +100 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/bin/src/happy-dom-sr.ts +30 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/package.json +62 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/ServerRenderer.ts +368 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/ServerRendererBrowser.ts +142 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/ServerRendererBrowserWorker.ts +29 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/ServerRendererPage.ts +305 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/ServerRendererPageWorker.ts +55 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/ServerRendererServer.ts +332 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/config/DefaultServerRendererConfiguration.ts +47 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/enums/ServerRendererLogLevelEnum.ts +9 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/enums/ServerRendererModeEnum.ts +8 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/index.ts +19 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/types/IOptionalServerRendererConfiguration.ts +127 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/types/IServerRendererConfiguration.ts +126 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/types/IServerRendererItem.ts +6 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/types/IServerRendererResult.ts +11 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/utilities/BrowserWindowPolyfill.ts +138 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/utilities/HelpPrinter.ts +36 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/utilities/HelpPrinterRows.ts +288 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/utilities/PackageVersion.ts +12 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/utilities/ProcessArgumentsParser.ts +387 -0
- package/vendor/happy-dom/packages/@happy-dom/server-renderer/src/utilities/ServerRendererConfigurationFactory.ts +91 -0
- package/vendor/happy-dom/packages/happy-dom/LICENSE +21 -0
- package/vendor/happy-dom/packages/happy-dom/README.md +42 -0
- package/vendor/happy-dom/packages/happy-dom/package.json +58 -0
- package/vendor/happy-dom/packages/happy-dom/src/PropertySymbol.ts +431 -0
- package/vendor/happy-dom/packages/happy-dom/src/animation/Animation.ts +273 -0
- package/vendor/happy-dom/packages/happy-dom/src/animation/AnimationTimeline.ts +15 -0
- package/vendor/happy-dom/packages/happy-dom/src/animation/DocumentTimeline.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/animation/KeyframeEffect.ts +295 -0
- package/vendor/happy-dom/packages/happy-dom/src/async-task-manager/AsyncTaskManager.ts +340 -0
- package/vendor/happy-dom/packages/happy-dom/src/async-task-manager/AsyncTaskManagerDebugError.ts +14 -0
- package/vendor/happy-dom/packages/happy-dom/src/base64/Base64.ts +97 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/Browser.ts +123 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/BrowserContext.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/BrowserFrame.ts +232 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/BrowserPage.ts +205 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/BrowserSettingsFactory.ts +96 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/DefaultBrowserSettings.ts +67 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/detached-browser/DetachedBrowser.ts +129 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/detached-browser/DetachedBrowserContext.ts +103 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/detached-browser/DetachedBrowserFrame.ts +250 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/detached-browser/DetachedBrowserPage.ts +218 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/enums/BrowserErrorCaptureEnum.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/enums/BrowserNavigationCrossOriginPolicyEnum.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IBrowser.ts +51 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IBrowserContext.ts +44 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IBrowserFrame.ts +112 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IBrowserPage.ts +110 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IBrowserPageViewport.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IBrowserSettings.ts +194 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IGoToOptions.ts +17 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IOptionalBrowserPageViewport.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IOptionalBrowserSettings.ts +190 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/types/IReloadOptions.ts +27 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserExceptionObserver.ts +123 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserFrameFactory.ts +106 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserFrameNavigator.ts +574 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserFrameScriptEvaluator.ts +71 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserFrameURL.ts +30 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserFrameValidator.ts +84 -0
- package/vendor/happy-dom/packages/happy-dom/src/browser/utilities/BrowserPageUtility.ts +56 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ICanvasAdapter.ts +63 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ICanvasAdapterCaller.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ICanvasGradient.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ICanvasPattern.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ICanvasRenderingContext2D.ts +162 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ICanvasShape.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/IImageBitmapOptions.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ITextMetrics.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ImageBitmap.ts +162 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/ImageData.ts +83 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/OffscreenCanvas.ts +162 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/TCanvasImage.ts +14 -0
- package/vendor/happy-dom/packages/happy-dom/src/canvas/TImageBitmapSource.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/clipboard/Clipboard.ts +108 -0
- package/vendor/happy-dom/packages/happy-dom/src/clipboard/ClipboardItem.ts +57 -0
- package/vendor/happy-dom/packages/happy-dom/src/config/HTMLElementConfig.ts +536 -0
- package/vendor/happy-dom/packages/happy-dom/src/config/HTMLElementConfigContentModelEnum.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/config/IHTMLElementTagNameMap.ts +181 -0
- package/vendor/happy-dom/packages/happy-dom/src/config/ISVGElementTagNameMap.ts +127 -0
- package/vendor/happy-dom/packages/happy-dom/src/config/NamespaceURI.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/config/SVGElementConfig.ts +70 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/IConsole.ts +161 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/IVirtualConsoleLogEntry.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/IVirtualConsoleLogGroup.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/IVirtualConsolePrinter.ts +58 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/VirtualConsole.ts +363 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/VirtualConsolePrinter.ts +148 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/enums/VirtualConsoleLogLevelEnum.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/enums/VirtualConsoleLogTypeEnum.ts +29 -0
- package/vendor/happy-dom/packages/happy-dom/src/console/utilities/VirtualConsoleLogEntryStringifier.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/CookieContainer.ts +91 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/DefaultCookie.ts +17 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/ICookie.ts +14 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/ICookieContainer.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/IOptionalCookie.ts +16 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/enums/CookieSameSiteEnum.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/urilities/CookieExpireUtility.ts +16 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/urilities/CookieStringUtility.ts +119 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie/urilities/CookieURLUtility.ts +27 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie-store/CookieStore.ts +226 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie-store/ICookieStoreDeleteOptions.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie-store/ICookieStoreGetOptions.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie-store/ICookieStoreItem.ts +13 -0
- package/vendor/happy-dom/packages/happy-dom/src/cookie-store/ICookieStoreSetOptions.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/CSS.ts +63 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/CSSRule.ts +84 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/CSSRuleTypeEnum.ts +18 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/CSSStyleSheet.ts +141 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/CSSUnitValue.ts +26 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/CSSUnits.ts +31 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/MediaList.ts +177 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/CSSPropertyList.ts +1273 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/CSSStyleDeclaration.ts +355 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/ICSSStyleDeclaration.ts +1178 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/computed-style/CSSComputedStyle.ts +502 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/computed-style/config/CSSComputedStyleElementDefault.ts +133 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/computed-style/config/CSSComputedStyleInheritedProperties.ts +39 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/computed-style/config/CSSComputedStyleMeasurementProperties.ts +41 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/CSSPropertyManager.ts +641 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/parsers/CSSPropertyGetParser.ts +741 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/parsers/CSSPropertySetParser.ts +2955 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/types/ICSSPropertyMap.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/types/ICSSPropertyValue.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/utilities/CSSStringUtility.ts +90 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/utilities/CSSValueFormatter.ts +447 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/property-manager/utilities/CSSVariableFormatter.ts +76 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/utilities/CSSMeasurementConverter.ts +79 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/declaration/utilities/CSSTextParser.ts +44 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSConditionRule.ts +20 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSContainerRule.ts +34 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSFontFaceRule.ts +45 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSGroupingRule.ts +84 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSKeyframeRule.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSKeyframesRule.ts +147 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSMediaRule.ts +50 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSScopeRule.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSStyleRule.ts +73 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/rules/CSSSupportsRule.ts +30 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/style-property-map/CSSKeywordValue.ts +35 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/style-property-map/CSSStyleValue.ts +37 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/style-property-map/StylePropertyMap.ts +45 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/style-property-map/StylePropertyMapReadOnly.ts +128 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/utilities/CSSEscaper.ts +87 -0
- package/vendor/happy-dom/packages/happy-dom/src/css/utilities/CSSRuleParser.ts +315 -0
- package/vendor/happy-dom/packages/happy-dom/src/custom-element/CustomElementReactionStack.ts +91 -0
- package/vendor/happy-dom/packages/happy-dom/src/custom-element/CustomElementRegistry.ts +186 -0
- package/vendor/happy-dom/packages/happy-dom/src/custom-element/CustomElementUtility.ts +34 -0
- package/vendor/happy-dom/packages/happy-dom/src/custom-element/ICustomElementDefinition.ts +16 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMPoint.ts +84 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMPointReadOnly.ts +117 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMRect.ts +92 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMRectList.ts +34 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMRectReadOnly.ts +129 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMStringMap.ts +93 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMStringMapUtility.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/DOMTokenList.ts +363 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/IDOMPointInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/IDOMRectInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/DOMMatrix.ts +526 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/DOMMatrixReadOnly.ts +1608 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/IDOMMatrixCompatibleObject.ts +24 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/IDOMMatrixJSON.ts +26 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/TDOMMatrix2DArray.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/TDOMMatrix3DArray.ts +20 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom/dom-matrix/TDOMMatrixInit.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom-implementation/DOMImplementation.ts +81 -0
- package/vendor/happy-dom/packages/happy-dom/src/dom-parser/DOMParser.ts +47 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/DataTransfer.ts +128 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/DataTransferItem.ts +47 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/DataTransferItemList.ts +44 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/Event.ts +222 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/EventPhaseEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/EventTarget.ts +396 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/IEventInit.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/IEventListenerOptions.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/ITouchInit.ts +16 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/IUIEventInit.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/MessagePort.ts +32 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/TEventListener.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/TEventListenerFunction.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/TEventListenerObject.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/Touch.ts +40 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/UIEvent.ts +32 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/AnimationEvent.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ClipboardEvent.ts +22 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/CloseEvent.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/CookieChangeEvent.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/CustomEvent.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ErrorEvent.ts +29 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/FocusEvent.ts +22 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/HashChangeEvent.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IAnimationEventInit.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IClipboardEventInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ICloseEventInit.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ICookieChangeEventInit.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ICustomEventInit.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IErrorEventInit.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IFocusEventInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IHashChangeEventInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IInputEventInit.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IKeyboardEventInit.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IMediaQueryListEventInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IMediaQueryListInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IMessageEventInit.ts +11 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IMouseEventInit.ts +21 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IPointerEventInit.ts +19 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IPopStateEventInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IProgressEventInit.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IStorageEventInit.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ISubmitEventInit.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ITouchEventInit.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/IWheelEventInit.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/InputEvent.ts +28 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/KeyboardEvent.ts +80 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/MediaQueryListEvent.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/MediaStreamTrackEvent.ts +22 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/MessageEvent.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/MouseEvent.ts +52 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/PointerEvent.ts +51 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/PopStateEvent.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/ProgressEvent.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/StorageEvent.ts +30 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/SubmitEvent.ts +22 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/TouchEvent.ts +34 -0
- package/vendor/happy-dom/packages/happy-dom/src/event/events/WheelEvent.ts +30 -0
- package/vendor/happy-dom/packages/happy-dom/src/exception/DOMException.ts +21 -0
- package/vendor/happy-dom/packages/happy-dom/src/exception/DOMExceptionNameEnum.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/AbortController.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/AbortSignal.ts +182 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/Fetch.ts +1072 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/Headers.ts +177 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/ReadableStreamWrapper.ts +30 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/Request.ts +492 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/ResourceFetch.ts +190 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/Response.ts +439 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/SyncFetch.ts +717 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/preflight/ICacheablePreflightRequest.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/preflight/ICacheablePreflightResponse.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/preflight/ICachedPreflightResponse.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/preflight/IPreflightResponseCache.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/preflight/PreflightResponseCache.ts +94 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/CachedResponseStateEnum.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/ICacheableRequest.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/ICacheableResponse.ts +11 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/ICachedResponse.ts +40 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/IResponseCache.ts +37 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/IResponseCacheFileSystem.ts +18 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/ResponseCache.ts +248 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/cache/response/ResponseCacheFileSystem.ts +175 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/certificate/FetchHTTPSCertificate.ts +52 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/data-uri/DataURIParser.ts +66 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/multipart/MultipartFormDataParser.ts +174 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/multipart/MultipartReader.ts +216 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/preload/PreloadEntry.ts +50 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/preload/PreloadUtility.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/IFetchInterceptor.ts +60 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/IFetchRequestHeaders.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/IRequestInit.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/IResourceFetchResponse.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/IResponseInit.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/ISyncResponse.ts +18 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/IVirtualServer.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/THeadersInit.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TRequestBody.ts +14 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TRequestCredentials.ts +1 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TRequestInfo.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TRequestMode.ts +1 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TRequestRedirect.ts +1 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TRequestReferrerPolicy.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/types/TResponseBody.ts +14 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchBodyUtility.ts +284 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchCORSUtility.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchRequestHeaderUtility.ts +141 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchRequestReferrerUtility.ts +259 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchRequestValidationUtility.ts +128 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchResponseHeaderUtility.ts +48 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/FetchResponseRedirectUtility.ts +27 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/SyncFetchScriptBuilder.ts +77 -0
- package/vendor/happy-dom/packages/happy-dom/src/fetch/utilities/VirtualServerUtility.ts +114 -0
- package/vendor/happy-dom/packages/happy-dom/src/file/Blob.ts +163 -0
- package/vendor/happy-dom/packages/happy-dom/src/file/File.ts +43 -0
- package/vendor/happy-dom/packages/happy-dom/src/file/FileReader.ts +211 -0
- package/vendor/happy-dom/packages/happy-dom/src/file/FileReaderEventTypeEnum.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/file/FileReaderFormatEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/file/FileReaderReadyStateEnum.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/form-data/FormData.ts +291 -0
- package/vendor/happy-dom/packages/happy-dom/src/history/History.ts +220 -0
- package/vendor/happy-dom/packages/happy-dom/src/history/HistoryItemList.ts +72 -0
- package/vendor/happy-dom/packages/happy-dom/src/history/HistoryScrollRestorationEnum.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/history/IHistoryItem.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/html-parser/HTMLParser.ts +920 -0
- package/vendor/happy-dom/packages/happy-dom/src/html-serializer/HTMLSerializer.ts +172 -0
- package/vendor/happy-dom/packages/happy-dom/src/index.ts +495 -0
- package/vendor/happy-dom/packages/happy-dom/src/intersection-observer/IIntersectionObserverInit.ts +16 -0
- package/vendor/happy-dom/packages/happy-dom/src/intersection-observer/IntersectionObserver.ts +64 -0
- package/vendor/happy-dom/packages/happy-dom/src/intersection-observer/IntersectionObserverEntry.ts +26 -0
- package/vendor/happy-dom/packages/happy-dom/src/javascript/IJavaScriptCompiledResult.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/javascript/JavaScriptCompiler.ts +381 -0
- package/vendor/happy-dom/packages/happy-dom/src/location/Location.ts +319 -0
- package/vendor/happy-dom/packages/happy-dom/src/match-media/IMediaQueryRange.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/match-media/IMediaQueryRule.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/match-media/MediaQueryItem.ts +354 -0
- package/vendor/happy-dom/packages/happy-dom/src/match-media/MediaQueryList.ts +133 -0
- package/vendor/happy-dom/packages/happy-dom/src/match-media/MediaQueryParser.ts +113 -0
- package/vendor/happy-dom/packages/happy-dom/src/match-media/MediaQueryTypeEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/CSSModule.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/ECMAScriptModule.ts +194 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/ECMAScriptModuleCompiler.ts +961 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/JSONModule.ts +58 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/ModuleFactory.ts +148 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/ModuleURLUtility.ts +199 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/UnresolvedModule.ts +81 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/enums/ECMAScriptModuleEvaluateStateEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IECMAScriptModuleCachedResult.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IECMAScriptModuleCompiledResult.ts +19 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IECMAScriptModuleImport.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IECMAScriptModuleInit.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IModule.ts +20 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IModuleImportMap.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IModuleImportMapRule.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IModuleImportMapScope.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IModuleInit.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/module/types/IResolveNodeModules.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/mutation-observer/IMutationListener.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/mutation-observer/IMutationObserverInit.ts +14 -0
- package/vendor/happy-dom/packages/happy-dom/src/mutation-observer/MutationObserver.ts +175 -0
- package/vendor/happy-dom/packages/happy-dom/src/mutation-observer/MutationObserverListener.ts +115 -0
- package/vendor/happy-dom/packages/happy-dom/src/mutation-observer/MutationRecord.ts +55 -0
- package/vendor/happy-dom/packages/happy-dom/src/mutation-observer/MutationTypeEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/navigator/MimeType.ts +35 -0
- package/vendor/happy-dom/packages/happy-dom/src/navigator/MimeTypeArray.ts +48 -0
- package/vendor/happy-dom/packages/happy-dom/src/navigator/Navigator.ts +247 -0
- package/vendor/happy-dom/packages/happy-dom/src/navigator/Plugin.ts +61 -0
- package/vendor/happy-dom/packages/happy-dom/src/navigator/PluginArray.ts +58 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/NodeFactory.ts +38 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/attr/Attr.ts +119 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/character-data/CharacterData.ts +218 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/character-data/CharacterDataUtility.ts +68 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/child-node/ChildNodeUtility.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/child-node/IChildNode.ts +29 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/child-node/INonDocumentTypeChildNode.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/child-node/NonDocumentChildNodeUtility.ts +37 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/comment/Comment.ts +36 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/document/Document.ts +2310 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/document/DocumentReadyStateEnum.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/document/DocumentReadyStateManager.ts +52 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/document/VisibilityStateEnum.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/document-fragment/DocumentFragment.ts +208 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/document-type/DocumentType.ts +70 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/Element.ts +1842 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/ElementEventAttributeUtility.ts +96 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/HTMLCollection.ts +228 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/NamedNodeMap.ts +274 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/NamedNodeMapProxyFactory.ts +127 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/THTMLCollectionListener.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/element/TNamedNodeMapListener.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-anchor-element/HTMLAnchorElement.ts +439 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-area-element/HTMLAreaElement.ts +426 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-audio-element/Audio.ts +28 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-audio-element/HTMLAudioElement.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-base-element/HTMLBaseElement.ts +64 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-body-element/HTMLBodyElement.ts +161 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-br-element/HTMLBRElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-button-element/HTMLButtonElement.ts +406 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-canvas-element/CanvasCaptureMediaStreamTrack.ts +51 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-canvas-element/HTMLCanvasElement.ts +304 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-d-list-element/HTMLDListElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-data-element/HTMLDataElement.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-data-list-element/HTMLDataListElement.ts +28 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-details-element/HTMLDetailsElement.ts +112 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-dialog-element/HTMLDialogElement.ts +104 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-div-element/HTMLDivElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-document/HTMLDocument.ts +82 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-element/HTMLElement.ts +1149 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-element/HTMLElementUtility.ts +119 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-embed-element/HTMLEmbedElement.ts +90 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-field-set-element/HTMLFieldSetElement.ts +165 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-form-element/HTMLFormControlsCollection.ts +35 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-form-element/HTMLFormElement.ts +675 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-form-element/RadioNodeList.ts +25 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-form-element/THTMLFormControlElement.ts +16 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-head-element/HTMLHeadElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-heading-element/HTMLHeadingElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-hr-element/HTMLHRElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-html-element/HTMLHtmlElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-hyperlink-element/HTMLHyperlinkElementUtility.ts +329 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-hyperlink-element/IHTMLHyperlinkElement.ts +19 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-iframe-element/HTMLIFrameElement.ts +460 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-image-element/HTMLImageElement.ts +500 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-image-element/Image.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/FileList.ts +34 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/HTMLInputElement.ts +1550 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/HTMLInputElementDateUtility.ts +50 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/HTMLInputElementSelectionDirectionEnum.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/HTMLInputElementSelectionModeEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/HTMLInputElementValueSanitizer.ts +211 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-input-element/HTMLInputElementValueStepping.ts +92 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElement.ts +128 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-label-element/HTMLLabelElementUtility.ts +45 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-legend-element/HTMLLegendElement.ts +27 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-li-element/HTMLLIElement.ts +31 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElement.ts +501 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-map-element/HTMLMapElement.ts +47 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/HTMLMediaElement.ts +906 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/IMediaTrackCapabilities.ts +21 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/IMediaTrackSettings.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/MediaStream.ts +114 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/MediaStreamTrack.ts +182 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/RemotePlayback.ts +47 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/TextTrack.ts +156 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/TextTrackCue.ts +51 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/TextTrackCueList.ts +37 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/TextTrackKindEnum.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/TextTrackList.ts +182 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/TimeRanges.ts +73 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/VTTCue.ts +80 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-media-element/VTTRegion.ts +15 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-menu-element/HTMLMenuElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-meta-element/HTMLMetaElement.ts +80 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-meter-element/HTMLMeterElement.ts +216 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-mod-element/HTMLModElement.ts +54 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-o-list-element/HTMLOListElement.ts +83 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-object-element/HTMLObjectElement.ts +223 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-opt-group-element/HTMLOptGroupElement.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-option-element/HTMLOptionElement.ts +192 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-output-element/HTMLOutputElement.ts +179 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-paragraph-element/HTMLParagraphElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-param-element/HTMLParamElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-picture-element/HTMLPictureElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-pre-element/HTMLPreElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-progress-element/HTMLProgressElement.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-quote-element/HTMLQuoteElement.ts +36 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts +735 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-select-element/HTMLOptionsCollection.ts +69 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-select-element/HTMLSelectElement.ts +779 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-slot-element/HTMLSlotElement.ts +249 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-source-element/HTMLSourceElement.ts +148 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-span-element/HTMLSpanElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-style-element/HTMLStyleElement.ts +125 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-table-caption-element/HTMLTableCaptionElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-table-cell-element/HTMLTableCellElement.ts +125 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-table-col-element/HTMLTableColElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-table-element/HTMLTableElement.ts +343 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-table-row-element/HTMLTableRowElement.ts +149 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-table-section-element/HTMLTableSectionElement.ts +88 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts +154 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-text-area-element/HTMLTextAreaElement.ts +649 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-time-element/HTMLTimeElement.ts +27 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-title-element/HTMLTitleElement.ts +48 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-track-element/HTMLTrackElement.ts +164 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-u-list-element/HTMLUListElement.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-unknown-element/HTMLUnknownElement.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/html-video-element/HTMLVideoElement.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedComputedStyleResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedElementByIdResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedElementByTagNameResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedElementsByTagNameResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedMatchesResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedQuerySelectorAllResult.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedQuerySelectorResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedResult.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/ICachedStyleResult.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/Node.ts +1373 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/NodeDocumentPositionEnum.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/NodeList.ts +224 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/NodeTypeEnum.ts +13 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/NodeUtility.ts +330 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/node/TNodeListListener.ts +1 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/parent-node/IParentNode.ts +109 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/parent-node/ParentNodeUtility.ts +334 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/processing-instruction/ProcessingInstruction.ts +22 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/shadow-root/ShadowRoot.ts +290 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-animate-element/SVGAnimateElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-animate-motion-element/SVGAnimateMotionElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-animate-transform-element/SVGAnimateTransformElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-animation-element/SVGAnimationElement.ts +94 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-circle-element/SVGCircleElement.ts +72 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-clip-path-element/SVGClipPathElement.ts +34 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-component-transfer-function-element/SVGComponentTransferFunctionElement.ts +167 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-defs-element/SVGDefsElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-desc-element/SVGDescElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-element/SVGElement.ts +828 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-ellipse-element/SVGEllipseElement.ts +92 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-blend-element/SVGFEBlendElement.ts +192 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-color-matrix-element/SVGFEColorMatrixElement.ts +204 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-component-transfer-element/SVGFEComponentTransferElement.ts +133 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-composite-element/SVGFECompositeElement.ts +186 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-convolve-matrix-element/SVGFEConvolveMatrixElement.ts +366 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-diffuse-lighting-element/SVGFEDiffuseLightingElement.ts +214 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-displacement-map-element/SVGFEDisplacementMapElement.ts +226 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-distant-light-element/SVGFEDistantLightElement.ts +52 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-drop-shadow-element/SVGFEDropShadowElement.ts +227 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-flood-element/SVGFEFloodElement.ts +113 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-func-a-element/SVGFEFuncAElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-func-b-element/SVGFEFuncBElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-func-g-element/SVGFEFuncGElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-func-r-element/SVGFEFuncRElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-gaussian-blur-element/SVGFEGaussianBlurElement.ts +214 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-image-element/SVGFEImageElement.ts +173 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-merge-element/SVGFEMergeElement.ts +113 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-merge-node-element/SVGFEMergeNodeElement.ts +32 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-morphology-element/SVGFEMorphologyElement.ts +202 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-offset-element/SVGFEOffsetElement.ts +174 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-point-light-element/SVGFEPointLightElement.ts +72 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-specular-lighting-element/SVGFESpecularLightingElement.ts +237 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-spot-light-element/SVGFESpotLightElement.ts +173 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-tile-element/SVGFETileElement.ts +133 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-fe-turbulence-element/SVGFETurbulenceElement.ts +249 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-filter-element/SVGFilterElement.ts +158 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-foreign-object-element/SVGForeignObjectElement.ts +92 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-g-element/SVGGElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-geometry-element/SVGGeometryElement.ts +94 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-gradient-element/SVGGradientElement.ts +104 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-graphics-element/SVGGraphicsElement.ts +134 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-image-element/SVGImageElement.ts +188 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-line-element/SVGLineElement.ts +92 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-linear-gradient-element/SVGLinearGradientElement.ts +92 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-m-path-element/SVGMPathElement.ts +32 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-marker-element/SVGMarkerElement.ts +230 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-mask-element/SVGMaskElement.ts +137 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-metadata-element/SVGMetadataElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-path-element/SVGPathElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-pattern-element/SVGPatternElement.ts +179 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-polygon-element/SVGPolygonElement.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-polyline-element/SVGPolylineElement.ts +53 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-radial-gradient-element/SVGRadialGradientElement.ts +112 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-rect-element/SVGRectElement.ts +132 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-script-element/SVGScriptElement.ts +50 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-set-element/SVGSetElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-stop-element/SVGStopElement.ts +32 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-style-element/SVGStyleElement.ts +143 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-svg-element/SVGSVGElement.ts +601 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-switch-element/SVGSwitchElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-symbol-element/SVGSymbolElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-t-span-element/SVGTSpanElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-text-content-element/SVGTextContentElement.ts +143 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-text-element/SVGTextElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-text-path-element/SVGTextPathElement.ts +106 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-text-positioning-element/SVGTextPositioningElement.ts +113 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-title-element/SVGTitleElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-use-element/SVGUseElement.ts +113 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/svg-view-element/SVGViewElement.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/text/Text.ts +154 -0
- package/vendor/happy-dom/packages/happy-dom/src/nodes/xml-document/XMLDocument.ts +10 -0
- package/vendor/happy-dom/packages/happy-dom/src/permissions/PermissionNameEnum.ts +32 -0
- package/vendor/happy-dom/packages/happy-dom/src/permissions/PermissionStatus.ts +23 -0
- package/vendor/happy-dom/packages/happy-dom/src/permissions/Permissions.ts +59 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/ISelectorAttribute.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/ISelectorMatch.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/ISelectorPseudo.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/QuerySelector.ts +849 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/SelectorCombinatorEnum.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/SelectorItem.ts +575 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/SelectorParser.ts +699 -0
- package/vendor/happy-dom/packages/happy-dom/src/query-selector/TGlobalMatchFunction.ts +12 -0
- package/vendor/happy-dom/packages/happy-dom/src/range/IRangeBoundaryPoint.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/range/Range.ts +1161 -0
- package/vendor/happy-dom/packages/happy-dom/src/range/RangeHowEnum.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/range/RangeUtility.ts +118 -0
- package/vendor/happy-dom/packages/happy-dom/src/resize-observer/ResizeObserver.ts +33 -0
- package/vendor/happy-dom/packages/happy-dom/src/screen/Screen.ts +19 -0
- package/vendor/happy-dom/packages/happy-dom/src/screen/ScreenDetailed.ts +17 -0
- package/vendor/happy-dom/packages/happy-dom/src/screen/ScreenDetails.ts +27 -0
- package/vendor/happy-dom/packages/happy-dom/src/selection/Selection.ts +556 -0
- package/vendor/happy-dom/packages/happy-dom/src/selection/SelectionDirectionEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/storage/Storage.ts +149 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAngle.ts +310 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAngleTypeEnum.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedAngle.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedBoolean.ts +80 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedEnumeration.ts +119 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedInteger.ts +97 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedLength.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedLengthList.ts +101 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedNumber.ts +101 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedNumberList.ts +101 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedPreserveAspectRatio.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedRect.ts +100 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedString.ts +83 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGAnimatedTransformList.ts +101 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGLength.ts +375 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGLengthList.ts +489 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGLengthTypeEnum.ts +15 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGMatrix.ts +429 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGNumber.ts +83 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGNumberList.ts +522 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGPoint.ts +114 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGPointList.ts +526 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGPreserveAspectRatio.ts +176 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGPreserveAspectRatioAlignEnum.ts +15 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGPreserveAspectRatioMeetOrSliceEnum.ts +7 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGRect.ts +200 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGStringList.ts +422 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGTransform.ts +369 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGTransformList.ts +531 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGTransformTypeEnum.ts +11 -0
- package/vendor/happy-dom/packages/happy-dom/src/svg/SVGUnitTypes.ts +26 -0
- package/vendor/happy-dom/packages/happy-dom/src/tree-walker/NodeFilter.ts +18 -0
- package/vendor/happy-dom/packages/happy-dom/src/tree-walker/NodeFilterMask.ts +28 -0
- package/vendor/happy-dom/packages/happy-dom/src/tree-walker/NodeIterator.ts +85 -0
- package/vendor/happy-dom/packages/happy-dom/src/tree-walker/TNodeFilter.ts +3 -0
- package/vendor/happy-dom/packages/happy-dom/src/tree-walker/TreeWalker.ts +339 -0
- package/vendor/happy-dom/packages/happy-dom/src/url/URL.ts +45 -0
- package/vendor/happy-dom/packages/happy-dom/src/utilities/AttributeUtility.ts +43 -0
- package/vendor/happy-dom/packages/happy-dom/src/utilities/ClassMethodBinder.ts +71 -0
- package/vendor/happy-dom/packages/happy-dom/src/utilities/StringUtility.ts +47 -0
- package/vendor/happy-dom/packages/happy-dom/src/utilities/XMLEncodeUtility.ts +166 -0
- package/vendor/happy-dom/packages/happy-dom/src/validity-state/ValidityState.ts +234 -0
- package/vendor/happy-dom/packages/happy-dom/src/version.ts +1 -0
- package/vendor/happy-dom/packages/happy-dom/src/web-socket/WebSocket.ts +408 -0
- package/vendor/happy-dom/packages/happy-dom/src/web-socket/WebSocketReadyStateEnum.ts +8 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/BrowserWindow.ts +3074 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/CrossOriginBrowserWindow.ts +152 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/DetachedWindowAPI.ts +133 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/GlobalWindow.ts +90 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/INodeJSGlobal.ts +76 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/IOptionalTimerLoopsLimit.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/IScrollToOptions.ts +5 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/ITimerLoopsLimit.ts +4 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/VMGlobalPropertyScript.ts +59 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/Window.ts +67 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/WindowBrowserContext.ts +117 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/WindowContextClassExtender.ts +288 -0
- package/vendor/happy-dom/packages/happy-dom/src/window/WindowPageOpenUtility.ts +200 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-http-request/XMLHttpRequest.ts +577 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-http-request/XMLHttpRequestEventTarget.ts +88 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-http-request/XMLHttpRequestReadyStateEnum.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-http-request/XMLHttpRequestResponseDataParser.ts +70 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-http-request/XMLHttpRequestUpload.ts +6 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-http-request/XMLHttpResponseTypeEnum.ts +9 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-parser/XMLParser.ts +744 -0
- package/vendor/happy-dom/packages/happy-dom/src/xml-serializer/XMLSerializer.ts +280 -0
- package/vendor/happy-dom/turbo.json +52 -0
- package/vendor/ses/LICENSE +201 -0
- package/vendor/ses/LICENSE-aura +16 -0
- package/vendor/ses/LICENSE-caja +13 -0
- package/vendor/ses/LICENSE-corejs +19 -0
- package/vendor/ses/LICENSE-v8 +9 -0
- package/vendor/ses/README.md +968 -0
- package/vendor/ses/dist/ses.mjs +15219 -0
- package/vendor/ses/package.json +142 -0
- package/vendor/wasmpeg/LICENSE +501 -0
- package/vendor/wasmpeg/NOTICE +30 -0
- package/vendor/wasmpeg/VENDORING.md +35 -0
- package/vendor/wasmpeg/dist/cpu.js +2 -0
- package/vendor/wasmpeg/dist/cpu.wasm +0 -0
- package/vendor/wasmpeg/package.json +45 -0
- package/vendor/wasmpeg/source-v1.0.1.tar.gz +0 -0
- package/vendor/wasmpeg/src/js/exec.mjs +478 -0
- package/vendor/wasmpeg/src/js/ffmpeg.js +94 -0
- package/vendor/wasmpeg/src/js/formats.js +84 -0
- package/vendor/wasmpeg/src/js/gpu.js +480 -0
- package/vendor/wasmpeg/src/js/index.d.ts +154 -0
- package/vendor/wasmpeg/src/js/index.js +7 -0
- package/vendor/wasmpeg/src/js/wasmpeg.mjs +221 -0
|
@@ -0,0 +1,2053 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initial style model informed by TermDOM's UA/cascade tests and UA element
|
|
3
|
+
* categories (bikeshaving/termdom, MIT, pinned in Architecture.md). The data
|
|
4
|
+
* model and parser here are project-owned and intentionally cover only the
|
|
5
|
+
* properties the current pixel renderer consumes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const BLOCK_TAGS = new Set([
|
|
9
|
+
"ADDRESS", "ARTICLE", "ASIDE", "BLOCKQUOTE", "BODY", "DD", "DETAILS", "DIV", "DL", "DT",
|
|
10
|
+
"FIELDSET", "FIGCAPTION", "FIGURE", "FOOTER", "FORM", "H1", "H2", "H3", "H4", "H5", "H6",
|
|
11
|
+
"HEADER", "HR", "HTML", "LI", "MAIN", "NAV", "OL", "P", "PRE", "SECTION", "UL",
|
|
12
|
+
]);
|
|
13
|
+
const NONE_TAGS = new Set(["HEAD", "LINK", "META", "NOFRAMES", "SCRIPT", "STYLE", "TEMPLATE", "TITLE"]);
|
|
14
|
+
const INHERITED = new Set([
|
|
15
|
+
"color", "font-family", "font-size", "font-weight", "line-height", "list-style-type", "text-align", "white-space",
|
|
16
|
+
"visibility", "overflow-wrap", "word-break", "border-spacing", "border-collapse",
|
|
17
|
+
]);
|
|
18
|
+
const LIST_STYLE_TYPES = new Set([
|
|
19
|
+
"none", "disc", "circle", "square", "decimal", "decimal-leading-zero",
|
|
20
|
+
"lower-alpha", "upper-alpha", "lower-latin", "upper-latin", "lower-roman", "upper-roman",
|
|
21
|
+
]);
|
|
22
|
+
const DISPLAYS = new Set([
|
|
23
|
+
"none", "block", "flex", "grid", "inline", "inline-block", "inline-flex", "inline-grid", "list-item",
|
|
24
|
+
"table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row",
|
|
25
|
+
"table-cell", "table-caption", "table-column", "table-column-group",
|
|
26
|
+
]);
|
|
27
|
+
/** CSS Fonts 4 §2.5 absolute-size keywords (medium = 16px). */
|
|
28
|
+
const FONT_SIZE_KEYWORDS = Object.freeze({
|
|
29
|
+
"xx-small": 9, "x-small": 10, small: 13, medium: 16, large: 18, "x-large": 24, "xx-large": 32, "xxx-large": 48,
|
|
30
|
+
});
|
|
31
|
+
/** HTML §15.3.8 table elements and their display types. */
|
|
32
|
+
const TABLE_DISPLAYS = new Map(Object.entries({
|
|
33
|
+
TABLE: "table", CAPTION: "table-caption", COLGROUP: "table-column-group", COL: "table-column",
|
|
34
|
+
THEAD: "table-header-group", TBODY: "table-row-group", TFOOT: "table-footer-group", TR: "table-row",
|
|
35
|
+
TD: "table-cell", TH: "table-cell",
|
|
36
|
+
}));
|
|
37
|
+
const VERTICAL_ALIGNS = new Set(["baseline", "top", "middle", "bottom", "text-top", "text-bottom", "sub", "super"]);
|
|
38
|
+
const AUTO_TRACK = Object.freeze({ min: "auto", max: "auto" });
|
|
39
|
+
const FLEX_ALIGNMENT = Object.freeze({ "flex-start": "start", "flex-end": "end", left: "start", right: "end" });
|
|
40
|
+
const GRADIENT = /^\s*(?:repeating-)?(?:linear|radial)-gradient\(/i;
|
|
41
|
+
const BOX_SIDES = Object.freeze(["top", "right", "bottom", "left"]);
|
|
42
|
+
const WHITE_SPACES = new Set(["normal", "nowrap", "pre", "pre-wrap"]);
|
|
43
|
+
// CSS Cascade 4 §7.3 CSS-wide keywords; revert is treated as unset (no user/UA origin split).
|
|
44
|
+
const CSS_WIDE_KEYWORDS = new Set(["inherit", "initial", "unset", "revert", "revert-layer"]);
|
|
45
|
+
// Computed-style fields a shorthand (or a property not named after its field) covers.
|
|
46
|
+
const PROPERTY_FIELDS = Object.freeze({
|
|
47
|
+
background: ["backgroundColor", "backgroundImage"],
|
|
48
|
+
flex: ["flexGrow", "flexShrink", "flexBasis"],
|
|
49
|
+
"flex-flow": ["flexDirection", "flexWrap"],
|
|
50
|
+
gap: ["rowGap", "columnGap", "gap"],
|
|
51
|
+
"grid-gap": ["rowGap", "columnGap", "gap"],
|
|
52
|
+
"grid-area": ["gridRowStart", "gridColumnStart", "gridRowEnd", "gridColumnEnd"],
|
|
53
|
+
"grid-row": ["gridRowStart", "gridRowEnd"],
|
|
54
|
+
"grid-column": ["gridColumnStart", "gridColumnEnd"],
|
|
55
|
+
"grid-template": ["gridTemplateColumns", "gridTemplateRows"],
|
|
56
|
+
"line-height": ["lineHeight", "lineHeightFactor"],
|
|
57
|
+
"list-style": ["listStyleType"],
|
|
58
|
+
"border-radius": ["borderRadius"],
|
|
59
|
+
"text-decoration": ["textDecorationLine", "textDecorationColor"],
|
|
60
|
+
"text-decoration-line": ["textDecorationLine"],
|
|
61
|
+
"text-decoration-color": ["textDecorationColor"],
|
|
62
|
+
top: ["inset"], right: ["inset"], bottom: ["inset"], left: ["inset"],
|
|
63
|
+
});
|
|
64
|
+
const BORDER_FIELDS = Object.freeze(["borderSpecifiedWidths", "borderStyles", "borderColors", "borderWidths"]);
|
|
65
|
+
|
|
66
|
+
const INITIAL = Object.freeze({
|
|
67
|
+
display: "inline",
|
|
68
|
+
// text-decoration: this element's own lines ("none" or an array) and color
|
|
69
|
+
// (null = currentColor); textDecorations adds what ancestors propagate.
|
|
70
|
+
textDecorationLine: "none",
|
|
71
|
+
textDecorationColor: null,
|
|
72
|
+
textDecorations: null,
|
|
73
|
+
color: "rgba(0, 0, 0, 1)",
|
|
74
|
+
backgroundColor: "rgba(0, 0, 0, 0)",
|
|
75
|
+
backgroundImage: null,
|
|
76
|
+
backgroundClip: "border-box",
|
|
77
|
+
boxShadow: null,
|
|
78
|
+
fontFamily: Object.freeze(["sans-serif"]),
|
|
79
|
+
fontSize: 16,
|
|
80
|
+
fontWeight: 400,
|
|
81
|
+
// null means `line-height: normal`, which layout resolves from font metrics.
|
|
82
|
+
lineHeight: null,
|
|
83
|
+
lineHeightFactor: null,
|
|
84
|
+
textAlign: "start",
|
|
85
|
+
whiteSpace: "normal",
|
|
86
|
+
listStyleType: "disc",
|
|
87
|
+
margin: Object.freeze([0, 0, 0, 0]),
|
|
88
|
+
padding: Object.freeze([0, 0, 0, 0]),
|
|
89
|
+
width: "auto",
|
|
90
|
+
height: "auto",
|
|
91
|
+
minWidth: "auto",
|
|
92
|
+
maxWidth: "none",
|
|
93
|
+
minHeight: "auto",
|
|
94
|
+
maxHeight: "none",
|
|
95
|
+
boxSizing: "content-box",
|
|
96
|
+
// Used border widths (0 where border-style is none/hidden), top/right/bottom/left.
|
|
97
|
+
borderWidths: Object.freeze([0, 0, 0, 0]),
|
|
98
|
+
borderColors: Object.freeze([null, null, null, null]),
|
|
99
|
+
borderStyles: Object.freeze(["none", "none", "none", "none"]),
|
|
100
|
+
borderSpecifiedWidths: Object.freeze([3, 3, 3, 3]),
|
|
101
|
+
borderRadius: 0,
|
|
102
|
+
flexDirection: "row",
|
|
103
|
+
flexWrap: "nowrap",
|
|
104
|
+
justifyContent: "normal",
|
|
105
|
+
alignItems: "normal",
|
|
106
|
+
alignSelf: "auto",
|
|
107
|
+
gap: 0,
|
|
108
|
+
rowGap: 0,
|
|
109
|
+
columnGap: 0,
|
|
110
|
+
flexGrow: 0,
|
|
111
|
+
flexShrink: 1,
|
|
112
|
+
flexBasis: "auto",
|
|
113
|
+
content: null,
|
|
114
|
+
position: "static",
|
|
115
|
+
// top/right/bottom/left: "auto", px, or a percentage of the containing block.
|
|
116
|
+
inset: Object.freeze(["auto", "auto", "auto", "auto"]),
|
|
117
|
+
zIndex: "auto",
|
|
118
|
+
transform: null,
|
|
119
|
+
justifyItems: "normal",
|
|
120
|
+
justifySelf: "auto",
|
|
121
|
+
gridTemplateColumns: null,
|
|
122
|
+
gridTemplateRows: null,
|
|
123
|
+
gridAutoColumns: Object.freeze([AUTO_TRACK]),
|
|
124
|
+
gridAutoRows: Object.freeze([AUTO_TRACK]),
|
|
125
|
+
gridAutoFlow: Object.freeze({ column: false, dense: false }),
|
|
126
|
+
gridColumnStart: "auto",
|
|
127
|
+
gridColumnEnd: "auto",
|
|
128
|
+
gridRowStart: "auto",
|
|
129
|
+
gridRowEnd: "auto",
|
|
130
|
+
// Painting only: visibility (inherited), group opacity, overflow clipping
|
|
131
|
+
// ("visible" or "clip"), and clip / clip-path rectangles.
|
|
132
|
+
float: "none",
|
|
133
|
+
// Tables: spacing [horizontal, vertical] (inherited), collapse, and cell alignment.
|
|
134
|
+
borderSpacing: Object.freeze([0, 0]),
|
|
135
|
+
borderCollapse: "separate",
|
|
136
|
+
tableLayout: "auto",
|
|
137
|
+
verticalAlign: "baseline",
|
|
138
|
+
visibility: "visible",
|
|
139
|
+
// Breaking inside words (CSS Text 3 §5): only with these set.
|
|
140
|
+
overflowWrap: "normal",
|
|
141
|
+
wordBreak: "normal",
|
|
142
|
+
opacity: 1,
|
|
143
|
+
overflowX: "visible",
|
|
144
|
+
overflowY: "visible",
|
|
145
|
+
textOverflow: "clip",
|
|
146
|
+
clip: null,
|
|
147
|
+
clipPath: null,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* User-agent defaults from the HTML Standard's suggested rendering rules
|
|
152
|
+
* (WHATWG HTML §15.3, CC BY 4.0) for the elements the renderer lays out.
|
|
153
|
+
*/
|
|
154
|
+
const UA_DECLARATIONS = new Map(Object.entries({
|
|
155
|
+
BODY: "margin: 8px",
|
|
156
|
+
P: "margin: 1em 0",
|
|
157
|
+
H1: "font-size: 2em; font-weight: bold; margin: 0.67em 0",
|
|
158
|
+
H2: "font-size: 1.5em; font-weight: bold; margin: 0.83em 0",
|
|
159
|
+
H3: "font-size: 1.17em; font-weight: bold; margin: 1em 0",
|
|
160
|
+
H4: "font-weight: bold; margin: 1.33em 0",
|
|
161
|
+
H5: "font-size: 0.83em; font-weight: bold; margin: 1.67em 0",
|
|
162
|
+
H6: "font-size: 0.67em; font-weight: bold; margin: 2.33em 0",
|
|
163
|
+
UL: "margin: 1em 0; padding-left: 40px; list-style-type: disc",
|
|
164
|
+
OL: "margin: 1em 0; padding-left: 40px; list-style-type: decimal",
|
|
165
|
+
DL: "margin: 1em 0",
|
|
166
|
+
DD: "margin-left: 40px",
|
|
167
|
+
BLOCKQUOTE: "margin: 1em 40px",
|
|
168
|
+
FIGURE: "margin: 1em 40px",
|
|
169
|
+
PRE: "margin: 1em 0; font-family: monospace",
|
|
170
|
+
CODE: "font-family: monospace",
|
|
171
|
+
KBD: "font-family: monospace",
|
|
172
|
+
SAMP: "font-family: monospace",
|
|
173
|
+
TT: "font-family: monospace",
|
|
174
|
+
HR: "margin: 0.5em 0; border: 1px solid gray",
|
|
175
|
+
// HTML §15.3.8 tables (vertical-align of rows and groups is inherited by cells).
|
|
176
|
+
TABLE: "border-spacing: 2px; border-collapse: separate",
|
|
177
|
+
THEAD: "vertical-align: middle",
|
|
178
|
+
TBODY: "vertical-align: middle",
|
|
179
|
+
TFOOT: "vertical-align: middle",
|
|
180
|
+
TR: "vertical-align: inherit",
|
|
181
|
+
TD: "padding: 1px; vertical-align: inherit",
|
|
182
|
+
TH: "padding: 1px; vertical-align: inherit; font-weight: bold; text-align: center",
|
|
183
|
+
CAPTION: "text-align: center",
|
|
184
|
+
}).map(([tag, source]) => [tag, parseDeclarations(source)]));
|
|
185
|
+
/**
|
|
186
|
+
* Form controls (HTML §15.5 describes their rendering only loosely): a 1px
|
|
187
|
+
* gray border, white field background and the 13.33px system font, close to
|
|
188
|
+
* what browsers draw. Checkboxes and radios are 13px boxes; the render tree
|
|
189
|
+
* fills them in when checked.
|
|
190
|
+
*/
|
|
191
|
+
const CONTROL_FONT = "font-size: 13.333px; font-family: sans-serif";
|
|
192
|
+
const FIELD = `${CONTROL_FONT}; border: 1px solid #767676; background-color: white`;
|
|
193
|
+
const BUTTON_LIKE = `${CONTROL_FONT}; border: 1px solid #767676; border-radius: 2px; padding: 1px 6px; background-color: #efefef; text-align: center`;
|
|
194
|
+
const UA_CONTROL_DECLARATIONS = Object.freeze({
|
|
195
|
+
textarea: parseDeclarations(`${FIELD}; font-family: monospace; padding: 2px; white-space: pre-wrap; overflow-wrap: break-word`),
|
|
196
|
+
text: parseDeclarations(`${FIELD}; padding: 1px 2px; white-space: pre`),
|
|
197
|
+
checkbox: parseDeclarations("width: 13px; height: 13px; margin: 3px 3px 3px 4px; border: 1px solid #767676; border-radius: 2px; background-color: white; box-sizing: border-box"),
|
|
198
|
+
radio: parseDeclarations("width: 13px; height: 13px; margin: 3px 3px 0 5px; border: 1px solid #767676; border-radius: 50%; background-color: white; box-sizing: border-box"),
|
|
199
|
+
button: parseDeclarations(`${BUTTON_LIKE}; white-space: pre`),
|
|
200
|
+
select: parseDeclarations(`${FIELD}; border-radius: 2px; padding: 0 4px; white-space: pre`),
|
|
201
|
+
});
|
|
202
|
+
const BUTTON_INPUTS = new Set(["button", "submit", "reset", "image", "file", "color"]);
|
|
203
|
+
|
|
204
|
+
/** Which UA control defaults an element gets, or null. */
|
|
205
|
+
export function controlKind(element) {
|
|
206
|
+
switch (element.tagName) {
|
|
207
|
+
case "TEXTAREA": return "textarea";
|
|
208
|
+
case "SELECT": return "select";
|
|
209
|
+
case "BUTTON": return "button";
|
|
210
|
+
case "INPUT": {
|
|
211
|
+
const type = String(element.getAttribute("type") ?? "text").toLowerCase();
|
|
212
|
+
if (type === "hidden") return "hidden";
|
|
213
|
+
if (type === "checkbox" || type === "radio") return type;
|
|
214
|
+
return BUTTON_INPUTS.has(type) ? "button" : "text";
|
|
215
|
+
}
|
|
216
|
+
default: return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** HTML §15.3.4: :link (visited links are not tracked). */
|
|
221
|
+
const UA_LINK_DECLARATIONS = parseDeclarations("color: #0000EE; text-decoration: underline; cursor: pointer");
|
|
222
|
+
const DECORATION_LINES = new Set(["underline", "overline", "line-through"]);
|
|
223
|
+
const DECORATION_STYLES = new Set(["solid", "double", "dotted", "dashed", "wavy"]);
|
|
224
|
+
|
|
225
|
+
const DEFAULT_ENVIRONMENT = Object.freeze({ viewportWidth: 800, viewportHeight: 600, rootFontSize: 16 });
|
|
226
|
+
let environment = DEFAULT_ENVIRONMENT;
|
|
227
|
+
|
|
228
|
+
export class StyleEngine {
|
|
229
|
+
#styles = new WeakMap();
|
|
230
|
+
#customProperties = new WeakMap();
|
|
231
|
+
#pseudoStyles = new WeakMap();
|
|
232
|
+
// Parsed and indexed rules for the last style sheet list and viewport:
|
|
233
|
+
// restyles after script changes reuse them instead of re-parsing.
|
|
234
|
+
#ruleCache = { styleSheets: null, key: "", index: null };
|
|
235
|
+
|
|
236
|
+
compute(document, styleSheets = [], viewport = {}) {
|
|
237
|
+
this.#styles = new WeakMap();
|
|
238
|
+
this.#customProperties = new WeakMap();
|
|
239
|
+
this.#pseudoStyles = new WeakMap();
|
|
240
|
+
const previous = environment;
|
|
241
|
+
environment = {
|
|
242
|
+
viewportWidth: viewport.width ?? DEFAULT_ENVIRONMENT.viewportWidth,
|
|
243
|
+
viewportHeight: viewport.height ?? DEFAULT_ENVIRONMENT.viewportHeight,
|
|
244
|
+
rootFontSize: DEFAULT_ENVIRONMENT.rootFontSize,
|
|
245
|
+
mobile: viewport.mobile === true,
|
|
246
|
+
};
|
|
247
|
+
try {
|
|
248
|
+
const rules = this.#rulesFor(styleSheets);
|
|
249
|
+
if (document.documentElement) this.#visit(document.documentElement, null, null, rules);
|
|
250
|
+
} finally {
|
|
251
|
+
environment = previous;
|
|
252
|
+
}
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
#rulesFor(styleSheets) {
|
|
257
|
+
const key = `${environment.viewportWidth}x${environment.viewportHeight}${environment.mobile ? ":mobile" : ""}`;
|
|
258
|
+
const cache = this.#ruleCache;
|
|
259
|
+
if (cache.styleSheets !== styleSheets || cache.key !== key || cache.length !== styleSheets.length) {
|
|
260
|
+
const counter = { order: 0 };
|
|
261
|
+
const rules = styleSheets.flatMap((source) => parseStyleSheet(source, environment, counter));
|
|
262
|
+
if (counter.layers) rankLayers(counter.layers, rules);
|
|
263
|
+
this.#ruleCache = { styleSheets, key, length: styleSheets.length, index: new RuleIndex(rules) };
|
|
264
|
+
}
|
|
265
|
+
return this.#ruleCache.index;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
get(element) {
|
|
269
|
+
return this.#styles.get(element) ?? INITIAL;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** The computed style of an element's ::before/::after box, or null when it generates none. */
|
|
273
|
+
getPseudo(element, pseudo) {
|
|
274
|
+
return this.#pseudoStyles.get(element)?.[pseudo] ?? null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#visit(element, parentStyle, parentCustomProperties, rules, ancestors = new Map()) {
|
|
278
|
+
const keys = elementKeys(element);
|
|
279
|
+
// Inline style takes part in the cascade before custom properties are
|
|
280
|
+
// resolved: style="--x: ..." must win over stylesheet values of --x.
|
|
281
|
+
const declarations = withInlineStyle(element, cascadeDeclarations(element, rules, null, keys, ancestors));
|
|
282
|
+
const customProperties = withCustomProperties(parentCustomProperties ?? EMPTY_MAP, declarations);
|
|
283
|
+
const style = computeElementStyle(element, parentStyle, declarations, customProperties);
|
|
284
|
+
// rem units resolve against the root element's computed font size.
|
|
285
|
+
if (!parentStyle) environment = { ...environment, rootFontSize: style.fontSize };
|
|
286
|
+
this.#styles.set(element, style);
|
|
287
|
+
this.#customProperties.set(element, customProperties);
|
|
288
|
+
const pseudoStyles = {};
|
|
289
|
+
for (const pseudo of ["before", "after"]) {
|
|
290
|
+
const pseudoDeclarations = cascadeDeclarations(element, rules, pseudo, keys, ancestors);
|
|
291
|
+
if (!pseudoDeclarations.has("content")) continue;
|
|
292
|
+
const pseudoCustom = withCustomProperties(customProperties, pseudoDeclarations);
|
|
293
|
+
const pseudoStyle = computeElementStyle(pseudoElement(pseudo), style, pseudoDeclarations, pseudoCustom);
|
|
294
|
+
// `content: none | normal` generates no box (CSS Pseudo 4 §2.3).
|
|
295
|
+
if (pseudoStyle.content != null && pseudoStyle.display !== "none") pseudoStyles[pseudo] = pseudoStyle;
|
|
296
|
+
}
|
|
297
|
+
if (pseudoStyles.before || pseudoStyles.after) this.#pseudoStyles.set(element, pseudoStyles);
|
|
298
|
+
// The element is an ancestor of everything below it.
|
|
299
|
+
const own = ancestorFilterKeys(keys);
|
|
300
|
+
for (const key of own) ancestors.set(key, (ancestors.get(key) ?? 0) + 1);
|
|
301
|
+
for (const child of element.children) this.#visit(child, style, customProperties, rules, ancestors);
|
|
302
|
+
for (const key of own) {
|
|
303
|
+
const count = ancestors.get(key) - 1;
|
|
304
|
+
if (count) ancestors.set(key, count);
|
|
305
|
+
else ancestors.delete(key);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const EMPTY_MAP = new Map();
|
|
311
|
+
|
|
312
|
+
/** The cascaded declarations with the element's style attribute applied on top. */
|
|
313
|
+
function withInlineStyle(element, declarations) {
|
|
314
|
+
const inline = element.getAttribute?.("style");
|
|
315
|
+
if (!inline) return declarations;
|
|
316
|
+
for (const declaration of parseDeclarations(inline).values()) {
|
|
317
|
+
const current = declarations.get(declaration.name);
|
|
318
|
+
if (!current?.important || declaration.important) {
|
|
319
|
+
declarations.set(declaration.name, { ...declaration, specificity: 1_000_000, order: Infinity });
|
|
320
|
+
if (declaration.name.startsWith("--")) declarations.hasCustomProperties = true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return declarations;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Custom properties after an element's declarations. Most elements declare
|
|
328
|
+
* none and share their parent's map; a copy is made only when one is set.
|
|
329
|
+
* (Copying a Map per element is slow once SES lockdown() has frozen the
|
|
330
|
+
* Map intrinsics, which disables JSC's fast paths for them.)
|
|
331
|
+
*/
|
|
332
|
+
function withCustomProperties(inherited, declarations) {
|
|
333
|
+
if (declarations.hasCustomProperties === false) return inherited;
|
|
334
|
+
let result = inherited;
|
|
335
|
+
for (const declaration of declarations.values()) {
|
|
336
|
+
if (!declaration.name.startsWith("--")) continue;
|
|
337
|
+
if (result === inherited) result = new Map(inherited);
|
|
338
|
+
result.set(declaration.name, declaration.value);
|
|
339
|
+
}
|
|
340
|
+
return result;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function computeElementStyle(element, parentStyle = null, authorDeclarations = null, customProperties = new Map()) {
|
|
344
|
+
const values = { ...INITIAL };
|
|
345
|
+
for (const property of INHERITED) {
|
|
346
|
+
if (parentStyle) copyProperty(values, property, parentStyle);
|
|
347
|
+
}
|
|
348
|
+
// vertical-align is not inherited, except through the table UA rules' "inherit".
|
|
349
|
+
values.verticalAlign = "baseline";
|
|
350
|
+
if (NONE_TAGS.has(element.tagName) || element.hasAttribute("hidden")) values.display = "none";
|
|
351
|
+
else if (TABLE_DISPLAYS.has(element.tagName)) values.display = TABLE_DISPLAYS.get(element.tagName);
|
|
352
|
+
else if (BLOCK_TAGS.has(element.tagName)) values.display = element.tagName === "LI" ? "list-item" : "block";
|
|
353
|
+
else if (["BUTTON", "INPUT", "SELECT", "TEXTAREA"].includes(element.tagName)) values.display = "inline-block";
|
|
354
|
+
if (["B", "STRONG"].includes(element.tagName)) values.fontWeight = 700;
|
|
355
|
+
if (element.tagName === "PRE") values.whiteSpace = "pre";
|
|
356
|
+
|
|
357
|
+
const declarations = new Map(authorDeclarations ?? []);
|
|
358
|
+
const isLink = (element.tagName === "A" || element.tagName === "AREA") && element.hasAttribute("href");
|
|
359
|
+
const control = controlKind(element);
|
|
360
|
+
if (control === "hidden") values.display = "none";
|
|
361
|
+
for (const declaration of [...(UA_DECLARATIONS.get(element.tagName)?.values() ?? []),
|
|
362
|
+
...(isLink ? UA_LINK_DECLARATIONS.values() : []), ...(UA_CONTROL_DECLARATIONS[control]?.values() ?? [])]) {
|
|
363
|
+
if (!declarations.has(declaration.name)) {
|
|
364
|
+
declarations.set(declaration.name, { ...declaration, specificity: -1, order: -1, layer: -Infinity });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
for (const declaration of parseDeclarations(element.getAttribute("style") ?? "").values()) {
|
|
368
|
+
const current = declarations.get(declaration.name);
|
|
369
|
+
if (!current?.important || declaration.important) {
|
|
370
|
+
declarations.set(declaration.name, { ...declaration, specificity: 1_000_000, order: Infinity });
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// The font size comes first (em lengths use it), from whichever of
|
|
374
|
+
// font-size and the font shorthand wins the cascade.
|
|
375
|
+
const fontSize = declarations.get("font-size");
|
|
376
|
+
const font = declarations.get("font");
|
|
377
|
+
const cascadeKey = (declaration) => ({ important: false, specificity: 0, order: 0, ...declaration, important: Boolean(declaration.important) });
|
|
378
|
+
if (font && (!fontSize || compareCascade(cascadeKey(font), cascadeKey(fontSize)) > 0)) {
|
|
379
|
+
const parsed = parseFontShorthand(resolveVariables(font.value, customProperties));
|
|
380
|
+
if (parsed) setProperty(values, "font-size", parsed.size, parentStyle);
|
|
381
|
+
} else if (fontSize) {
|
|
382
|
+
applyDeclaration(values, fontSize, customProperties, parentStyle);
|
|
383
|
+
}
|
|
384
|
+
// Apply in cascade order so a later shorthand overrides earlier longhands and vice versa.
|
|
385
|
+
const ordered = [...declarations.values()].sort((left, right) => compareCascade(
|
|
386
|
+
{ important: false, specificity: 0, order: 0, ...left, important: Boolean(left.important) },
|
|
387
|
+
{ important: false, specificity: 0, order: 0, ...right, important: Boolean(right.important) },
|
|
388
|
+
));
|
|
389
|
+
for (const declaration of ordered) {
|
|
390
|
+
if (declaration.name.startsWith("--") || declaration.name === "font-size") continue;
|
|
391
|
+
// The shorthand's size was settled above; its other parts apply in order.
|
|
392
|
+
applyDeclaration(values, declaration.name === "font" ? { ...declaration, name: "font-parts" } : declaration, customProperties, parentStyle);
|
|
393
|
+
}
|
|
394
|
+
// Floats (approximation): laid out as atomic inlines in the line, left floats
|
|
395
|
+
// in order and right floats at the line's end. Absolutely positioned boxes
|
|
396
|
+
// and flex/grid items do not float (CSS 2 §9.7, Flexbox §4, Grid §6).
|
|
397
|
+
const parentDisplay = parentStyle?.display ?? "block";
|
|
398
|
+
const flexOrGridItem = ["flex", "inline-flex", "grid", "inline-grid"].includes(parentDisplay);
|
|
399
|
+
if (values.float !== "none" && (["absolute", "fixed"].includes(values.position) || flexOrGridItem)) values.float = "none";
|
|
400
|
+
if (values.float !== "none" && values.display !== "none") {
|
|
401
|
+
values.display = { flex: "inline-flex", grid: "inline-grid", "inline-flex": "inline-flex", "inline-grid": "inline-grid" }[values.display]
|
|
402
|
+
?? "inline-block";
|
|
403
|
+
}
|
|
404
|
+
// A border side is only drawn with a visible style; currentColor follows `color`.
|
|
405
|
+
values.borderWidths = Object.freeze(values.borderSpecifiedWidths.map((width, index) =>
|
|
406
|
+
["none", "hidden"].includes(values.borderStyles[index]) ? 0 : width));
|
|
407
|
+
values.borderColors = Object.freeze(values.borderColors.map((color) => color ?? values.color));
|
|
408
|
+
values.borderStyles = Object.freeze([...values.borderStyles]);
|
|
409
|
+
values.borderSpecifiedWidths = Object.freeze([...values.borderSpecifiedWidths]);
|
|
410
|
+
// A unitless line-height inherits as a factor of each element's own font size.
|
|
411
|
+
if (values.lineHeightFactor != null) values.lineHeight = values.lineHeightFactor * values.fontSize;
|
|
412
|
+
if (values.color === "rgba(0, 0, 0, 0)" && values.backgroundClip === "text" && values.backgroundImage) {
|
|
413
|
+
values.color = gradientFallbackColor(values.backgroundImage) ?? values.color;
|
|
414
|
+
}
|
|
415
|
+
// Text decorations propagate to in-flow descendants, but not into atomic
|
|
416
|
+
// inlines or out-of-flow boxes (CSS Text Decoration 3 §2.1). Each ancestor's
|
|
417
|
+
// lines keep their own color in the spec; here the innermost color wins.
|
|
418
|
+
const atomic = /^inline-/.test(values.display) || ["absolute", "fixed"].includes(values.position);
|
|
419
|
+
let decorations = atomic ? null : parentStyle?.textDecorations ?? null;
|
|
420
|
+
if (Array.isArray(values.textDecorationLine)) {
|
|
421
|
+
decorations = Object.freeze({
|
|
422
|
+
lines: Object.freeze([...new Set([...(decorations?.lines ?? []), ...values.textDecorationLine])]),
|
|
423
|
+
color: values.textDecorationColor ?? values.color,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
values.textDecorations = decorations;
|
|
427
|
+
if (control === "textarea" || control === "text") applyControlSize(element, control, values);
|
|
428
|
+
values.margin = Object.freeze(values.margin);
|
|
429
|
+
values.inset = Object.freeze([...values.inset]);
|
|
430
|
+
values.padding = Object.freeze(values.padding);
|
|
431
|
+
return Object.freeze(values);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* A declaration block, parsed on first use. A large site ships tens of
|
|
436
|
+
* thousands of rules and only a few percent ever match, so blocks are kept
|
|
437
|
+
* as ranges of the sheet text until a rule applies (the idea of Blink's
|
|
438
|
+
* CSSLazyParsingState, core/css/parser/css_lazy_parsing_state.cc, BSD).
|
|
439
|
+
*/
|
|
440
|
+
class DeclarationBlock {
|
|
441
|
+
#css;
|
|
442
|
+
#start;
|
|
443
|
+
#end;
|
|
444
|
+
#parsed = null;
|
|
445
|
+
|
|
446
|
+
constructor(css, start, end) {
|
|
447
|
+
this.#css = css;
|
|
448
|
+
this.#start = start;
|
|
449
|
+
this.#end = end;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
#parse() {
|
|
453
|
+
if (!this.#parsed) {
|
|
454
|
+
const map = parseDeclarations(this.#css.slice(this.#start, this.#end));
|
|
455
|
+
// Arrays and flags for the cascade loop: iterating Maps is slow once SES
|
|
456
|
+
// lockdown() has frozen their intrinsics.
|
|
457
|
+
const list = [...map.values()];
|
|
458
|
+
this.#parsed = { map, list, custom: list.some((declaration) => declaration.name.startsWith("--")) };
|
|
459
|
+
this.#css = null;
|
|
460
|
+
}
|
|
461
|
+
return this.#parsed;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
get map() {
|
|
465
|
+
return this.#parse().map;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
get list() {
|
|
469
|
+
return this.#parse().list;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
get hasCustomProperties() {
|
|
473
|
+
return this.#parse().custom;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* One selector of a style rule. Specificity and declarations are computed on
|
|
479
|
+
* first use: most selectors of a large site never match.
|
|
480
|
+
*/
|
|
481
|
+
class StyleRule {
|
|
482
|
+
#selectorText;
|
|
483
|
+
#specificity = null;
|
|
484
|
+
#block;
|
|
485
|
+
|
|
486
|
+
constructor(selector, selectorText, pseudo, block, order) {
|
|
487
|
+
this.selector = selector;
|
|
488
|
+
this.#selectorText = selectorText;
|
|
489
|
+
this.pseudo = pseudo;
|
|
490
|
+
this.#block = block;
|
|
491
|
+
this.order = order;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
get specificity() {
|
|
495
|
+
return this.#specificity ??= selectorSpecificity(this.#selectorText);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
get declarations() {
|
|
499
|
+
return this.#block.map;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
get declarationList() {
|
|
503
|
+
return this.#block.list;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
get hasCustomProperties() {
|
|
507
|
+
return this.#block.hasCustomProperties;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Parses style rules, descending into conditional group rules. `@media` is
|
|
513
|
+
* evaluated against the viewport; `@supports` and `@layer` blocks are applied;
|
|
514
|
+
* other at-rules (`@font-face`, `@keyframes`, ...) are skipped.
|
|
515
|
+
*/
|
|
516
|
+
export function parseStyleSheet(source, viewport = environment, counter = { order: 0 }) {
|
|
517
|
+
const rules = [];
|
|
518
|
+
const css = String(source).replace(/\/\*[\s\S]*?\*\//g, "");
|
|
519
|
+
// Cascade layers are ordered across every sheet parsed with this counter.
|
|
520
|
+
counter.layers ??= newLayer(null);
|
|
521
|
+
|
|
522
|
+
function parseBlock(start, end, layer = null) {
|
|
523
|
+
let index = start;
|
|
524
|
+
while (index < end) {
|
|
525
|
+
const open = findTopLevel(css, "{", index, end);
|
|
526
|
+
const semicolon = findTopLevel(css, ";", index, end);
|
|
527
|
+
if (semicolon !== -1 && (open === -1 || semicolon < open)) {
|
|
528
|
+
// `@layer a, b;` declares layer order without rules.
|
|
529
|
+
const statement = css.slice(index, semicolon).trim();
|
|
530
|
+
if (/^@layer\s/i.test(statement)) {
|
|
531
|
+
for (const name of statement.slice(6).split(",").map((part) => part.trim()).filter(Boolean)) {
|
|
532
|
+
declareLayer(layer ?? counter.layers, name);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
index = semicolon + 1;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (open === -1) break;
|
|
539
|
+
const close = matchingBrace(css, open, end);
|
|
540
|
+
const prelude = css.slice(index, open).trim();
|
|
541
|
+
if (prelude.startsWith("@")) {
|
|
542
|
+
const name = /^@([\w-]+)/.exec(prelude)?.[1]?.toLowerCase();
|
|
543
|
+
const condition = prelude.slice(name ? name.length + 1 : 1).trim();
|
|
544
|
+
if (name === "layer") {
|
|
545
|
+
// A named layer block, or an anonymous one (a layer of its own).
|
|
546
|
+
const parent = layer ?? counter.layers;
|
|
547
|
+
const inner = condition ? declareLayer(parent, condition) : declareLayer(parent, `\0anonymous${counter.order}`);
|
|
548
|
+
parseBlock(open + 1, close, inner);
|
|
549
|
+
} else if ((name === "media" && mediaQueryMatches(condition, viewport)) || name === "supports") {
|
|
550
|
+
parseBlock(open + 1, close, layer);
|
|
551
|
+
}
|
|
552
|
+
} else if (prelude) {
|
|
553
|
+
const block = new DeclarationBlock(css, open + 1, close);
|
|
554
|
+
for (const selectorText of splitTopLevel(prelude, ",").filter(Boolean)) {
|
|
555
|
+
const { selector, pseudo } = splitPseudoElement(selectorText);
|
|
556
|
+
if (pseudo === undefined) continue;
|
|
557
|
+
const rule = new StyleRule(selector, selectorText, pseudo, block, counter.order++);
|
|
558
|
+
rule.layerNode = layer;
|
|
559
|
+
rules.push(rule);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
index = close + 1;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
parseBlock(0, css.length);
|
|
567
|
+
return rules;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function newLayer(parent) {
|
|
571
|
+
return { parent, children: new Map(), rank: Infinity };
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/** Finds or creates a (possibly dotted) layer name under `parent`, in first-seen order. */
|
|
575
|
+
function declareLayer(parent, name) {
|
|
576
|
+
let node = parent;
|
|
577
|
+
for (const part of name.split(".").map((piece) => piece.trim()).filter(Boolean)) {
|
|
578
|
+
let child = node.children.get(part);
|
|
579
|
+
if (!child) node.children.set(part, child = newLayer(node));
|
|
580
|
+
node = child;
|
|
581
|
+
}
|
|
582
|
+
return node;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Cascade layer ranks (CSS Cascade 5 §6.4): layers in first-seen order, a
|
|
587
|
+
* layer's sublayers before its own rules; unlayered rules rank highest.
|
|
588
|
+
*/
|
|
589
|
+
export function rankLayers(root, rules) {
|
|
590
|
+
let next = 0;
|
|
591
|
+
(function visit(node) {
|
|
592
|
+
for (const child of node.children.values()) visit(child);
|
|
593
|
+
if (node !== root) node.rank = next++;
|
|
594
|
+
})(root);
|
|
595
|
+
for (const rule of rules) rule.layer = rule.layerNode ? rule.layerNode.rank : Infinity;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** Splits a `font` shorthand value into size, line height, weight and family. */
|
|
599
|
+
function parseFontShorthand(value) {
|
|
600
|
+
const tokens = splitTopLevel(value, " ").filter(Boolean);
|
|
601
|
+
let weight = null;
|
|
602
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
603
|
+
const token = tokens[index];
|
|
604
|
+
const lower = token.toLowerCase();
|
|
605
|
+
if (["normal", "italic", "oblique", "small-caps"].includes(lower) || /^(?:ultra-|extra-|semi-)?(?:condensed|expanded)$/.test(lower)) continue;
|
|
606
|
+
if (["bold", "bolder", "lighter"].includes(lower) || /^[1-9]00$/.test(lower)) {
|
|
607
|
+
weight = lower === "bolder" ? "700" : lower === "lighter" ? "300" : lower;
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
// The size, optionally with /line-height, then the family list.
|
|
611
|
+
const [size, lineHeight] = token.split("/");
|
|
612
|
+
const family = tokens.slice(index + 1).join(" ").trim();
|
|
613
|
+
if (!family || !(FONT_SIZE_KEYWORDS[size] || /^[\d.]/.test(size) || /^(?:calc|clamp|min|max)\(/.test(size))) return null;
|
|
614
|
+
return { size, lineHeight: lineHeight || null, weight, family };
|
|
615
|
+
}
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function findTopLevel(source, character, start, end) {
|
|
620
|
+
let quote = "";
|
|
621
|
+
let depth = 0;
|
|
622
|
+
for (let index = start; index < end; index++) {
|
|
623
|
+
const current = source[index];
|
|
624
|
+
if (quote) {
|
|
625
|
+
if (current === "\\") index++;
|
|
626
|
+
else if (current === quote) quote = "";
|
|
627
|
+
} else if (current === '"' || current === "'") quote = current;
|
|
628
|
+
else if (current === "(") depth++;
|
|
629
|
+
else if (current === ")") depth = Math.max(0, depth - 1);
|
|
630
|
+
else if (current === character && depth === 0) return index;
|
|
631
|
+
else if (current === "{" || current === "}") return character === current ? index : -1;
|
|
632
|
+
}
|
|
633
|
+
return -1;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function matchingBrace(source, open, end) {
|
|
637
|
+
let depth = 0;
|
|
638
|
+
let quote = "";
|
|
639
|
+
for (let index = open; index < end; index++) {
|
|
640
|
+
const current = source[index];
|
|
641
|
+
if (quote) {
|
|
642
|
+
if (current === "\\") index++;
|
|
643
|
+
else if (current === quote) quote = "";
|
|
644
|
+
} else if (current === '"' || current === "'") quote = current;
|
|
645
|
+
else if (current === "{") depth++;
|
|
646
|
+
else if (current === "}" && --depth === 0) return index;
|
|
647
|
+
}
|
|
648
|
+
return end;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/** Evaluates a media query list for a screen viewport (light scheme, no print). */
|
|
652
|
+
export function mediaQueryMatches(query, viewport = environment) {
|
|
653
|
+
const width = viewport.viewportWidth ?? viewport.width ?? DEFAULT_ENVIRONMENT.viewportWidth;
|
|
654
|
+
const height = viewport.viewportHeight ?? viewport.height ?? DEFAULT_ENVIRONMENT.viewportHeight;
|
|
655
|
+
const mobile = viewport.mobile === true;
|
|
656
|
+
const text = query.trim().toLowerCase();
|
|
657
|
+
if (!text) return true;
|
|
658
|
+
return splitTopLevel(text, ",").some((single) => {
|
|
659
|
+
let negate = false;
|
|
660
|
+
let rest = single.trim();
|
|
661
|
+
if (rest.startsWith("not ")) {
|
|
662
|
+
negate = true;
|
|
663
|
+
rest = rest.slice(4).trim();
|
|
664
|
+
}
|
|
665
|
+
rest = rest.replace(/^only\s+/, "");
|
|
666
|
+
const matches = rest.split(/\s+and\s+/).every((part) => {
|
|
667
|
+
part = part.trim();
|
|
668
|
+
if (["all", "screen"].includes(part)) return true;
|
|
669
|
+
if (/^[a-z-]+$/.test(part)) return false;
|
|
670
|
+
const feature = /^\(\s*([a-z-]+)\s*(?::\s*(.+?))?\s*\)$/.exec(part);
|
|
671
|
+
if (feature) return mediaFeatureMatches(feature[1], feature[2], width, height, mobile);
|
|
672
|
+
const range = /^\(\s*(width|height)\s*(<=|>=|<|>|=)\s*(.+?)\s*\)$/.exec(part);
|
|
673
|
+
if (!range) return false;
|
|
674
|
+
const actual = range[1] === "width" ? width : height;
|
|
675
|
+
const limit = mediaLength(range[3]);
|
|
676
|
+
return { "<=": actual <= limit, ">=": actual >= limit, "<": actual < limit, ">": actual > limit, "=": actual === limit }[range[2]];
|
|
677
|
+
});
|
|
678
|
+
return negate ? !matches : matches;
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function mediaFeatureMatches(name, value, width, height, mobile = false) {
|
|
683
|
+
switch (name) {
|
|
684
|
+
// Input features are only answered in --mobile mode (a touch screen);
|
|
685
|
+
// otherwise they match nothing, as before.
|
|
686
|
+
case "hover":
|
|
687
|
+
case "any-hover":
|
|
688
|
+
return mobile && value === "none";
|
|
689
|
+
case "pointer":
|
|
690
|
+
case "any-pointer":
|
|
691
|
+
return mobile && (value === undefined || value === "coarse");
|
|
692
|
+
case "min-width": return width >= mediaLength(value);
|
|
693
|
+
case "max-width": return width <= mediaLength(value);
|
|
694
|
+
case "min-height": return height >= mediaLength(value);
|
|
695
|
+
case "max-height": return height <= mediaLength(value);
|
|
696
|
+
case "orientation": return value === (height >= width ? "portrait" : "landscape");
|
|
697
|
+
case "prefers-color-scheme": return value === "light";
|
|
698
|
+
case "prefers-reduced-motion": return value === "no-preference";
|
|
699
|
+
case "color": return true;
|
|
700
|
+
default: return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function mediaLength(value) {
|
|
705
|
+
// Media queries resolve em/rem against the initial font size, not the root style.
|
|
706
|
+
const match = /^([+-]?(?:\d+\.?\d*|\.\d+))(px|em|rem)?$/.exec(String(value).trim());
|
|
707
|
+
if (!match) return NaN;
|
|
708
|
+
return Number(match[1]) * (match[2] && match[2] !== "px" ? DEFAULT_ENVIRONMENT.rootFontSize : 1);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export function parseDeclarations(source) {
|
|
712
|
+
const declarations = new Map();
|
|
713
|
+
for (const part of splitDeclarations(String(source))) {
|
|
714
|
+
const colon = part.indexOf(":");
|
|
715
|
+
if (colon < 1) continue;
|
|
716
|
+
// Custom property names are case-sensitive (CSS Variables 1 §2).
|
|
717
|
+
const rawName = part.slice(0, colon).trim();
|
|
718
|
+
const name = rawName.startsWith("--") ? rawName : rawName.toLowerCase();
|
|
719
|
+
let value = part.slice(colon + 1).trim();
|
|
720
|
+
const important = /\s*!important\s*$/i.test(value);
|
|
721
|
+
value = value.replace(/\s*!important\s*$/i, "").trim();
|
|
722
|
+
if (!name || !value || (declarations.get(name)?.important && !important)) continue;
|
|
723
|
+
declarations.set(name, { name, value, important });
|
|
724
|
+
}
|
|
725
|
+
return declarations;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const reportedDeclarationErrors = new Set();
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Applies one cascaded declaration. A declaration the engine cannot handle is
|
|
732
|
+
* dropped, as an invalid declaration would be, instead of failing the page.
|
|
733
|
+
*/
|
|
734
|
+
function applyDeclaration(style, declaration, customProperties, parentStyle) {
|
|
735
|
+
try {
|
|
736
|
+
setProperty(style, declaration.name, resolveVariables(declaration.value, customProperties), parentStyle);
|
|
737
|
+
} catch (error) {
|
|
738
|
+
const key = `${declaration.name}: ${declaration.value}`;
|
|
739
|
+
if (reportedDeclarationErrors.size < 100 && !reportedDeclarationErrors.has(key)) {
|
|
740
|
+
reportedDeclarationErrors.add(key);
|
|
741
|
+
console.error(`buninu-browser: style: dropped "${key}": ${error?.message ?? error}`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function setProperty(style, name, value, parentStyle = null) {
|
|
747
|
+
if (CSS_WIDE_KEYWORDS.has(value)) {
|
|
748
|
+
const inherits = value === "inherit" || (value !== "initial" && INHERITED.has(name));
|
|
749
|
+
copyProperty(style, name, inherits && parentStyle ? parentStyle : INITIAL);
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (typeof value !== "string") return;
|
|
753
|
+
switch (name) {
|
|
754
|
+
case "display": if (DISPLAYS.has(value)) style.display = value; break;
|
|
755
|
+
case "text-decoration-line": {
|
|
756
|
+
const lines = parseDecorationLines(value);
|
|
757
|
+
if (lines) style.textDecorationLine = lines;
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
case "text-decoration-color": {
|
|
761
|
+
if (value.toLowerCase() === "currentcolor") style.textDecorationColor = null;
|
|
762
|
+
else if (Bun.color(value, "rgba")) style.textDecorationColor = Bun.color(value, "rgba");
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
765
|
+
case "text-decoration": {
|
|
766
|
+
// <line> || <style> || <color> || <thickness>; only lines and color are drawn.
|
|
767
|
+
let lines = "none";
|
|
768
|
+
let color = null;
|
|
769
|
+
for (const token of splitTopLevel(value, " ").filter(Boolean)) {
|
|
770
|
+
const lower = token.toLowerCase();
|
|
771
|
+
if (DECORATION_LINES.has(lower) || lower === "none") {
|
|
772
|
+
const parsed = parseDecorationLines(lower === "none" ? "none" : [...(Array.isArray(lines) ? lines : []), lower].join(" "));
|
|
773
|
+
if (!parsed) return;
|
|
774
|
+
lines = parsed;
|
|
775
|
+
} else if (DECORATION_STYLES.has(lower) || lower === "auto" || lower === "from-font"
|
|
776
|
+
|| Number.isFinite(computedLength(token, style.fontSize, true)) || /%$/.test(token)) {
|
|
777
|
+
continue;
|
|
778
|
+
} else if (lower === "currentcolor") {
|
|
779
|
+
color = null;
|
|
780
|
+
} else if (Bun.color(token, "rgba")) {
|
|
781
|
+
color = Bun.color(token, "rgba");
|
|
782
|
+
} else {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
style.textDecorationLine = lines;
|
|
787
|
+
style.textDecorationColor = color;
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
case "visibility":
|
|
791
|
+
if (["visible", "hidden", "collapse"].includes(value)) style.visibility = value === "collapse" ? "hidden" : value;
|
|
792
|
+
break;
|
|
793
|
+
case "opacity": {
|
|
794
|
+
const number = /^([+-]?(?:\d+\.?\d*|\.\d+))(%?)$/.exec(value);
|
|
795
|
+
if (number) style.opacity = Math.min(1, Math.max(0, Number(number[1]) / (number[2] ? 100 : 1)));
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
case "overflow":
|
|
799
|
+
case "overflow-x":
|
|
800
|
+
case "overflow-y": {
|
|
801
|
+
// Scrolling boxes are not implemented: every non-visible value clips.
|
|
802
|
+
const parts = value.split(/\s+/);
|
|
803
|
+
const clips = (part) => (["hidden", "clip", "auto", "scroll", "overlay"].includes(part) ? "clip" : part === "visible" ? "visible" : null);
|
|
804
|
+
const x = clips(parts[0]);
|
|
805
|
+
const y = clips(parts[1] ?? parts[0]);
|
|
806
|
+
if (name !== "overflow-y" && x) style.overflowX = x;
|
|
807
|
+
if (name !== "overflow-x" && (name === "overflow" ? y : x)) style.overflowY = name === "overflow" ? y : x;
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
case "text-overflow":
|
|
811
|
+
if (["clip", "ellipsis"].includes(value)) style.textOverflow = value;
|
|
812
|
+
break;
|
|
813
|
+
case "clip": {
|
|
814
|
+
// CSS 2 clip (absolutely positioned boxes): rect(top, right, bottom, left), auto keeps an edge.
|
|
815
|
+
if (value === "auto") style.clip = null;
|
|
816
|
+
const rect = /^rect\(\s*(.*)\s*\)$/i.exec(value);
|
|
817
|
+
if (rect) {
|
|
818
|
+
const edges = rect[1].split(/\s*,\s*|\s+/).map((part) => (part === "auto" ? "auto" : computedLength(part, style.fontSize)));
|
|
819
|
+
if (edges.length === 4 && edges.every((edge) => edge === "auto" || Number.isFinite(edge))) style.clip = Object.freeze(edges);
|
|
820
|
+
}
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
case "clip-path": {
|
|
824
|
+
// Only rectangles: inset(top right bottom left) and rect(0 0 0 0)-style empty clips.
|
|
825
|
+
if (value === "none") style.clipPath = null;
|
|
826
|
+
const inset = /^inset\(\s*([^)]*?)\s*(?:round\s[^)]*)?\)$/i.exec(value);
|
|
827
|
+
if (inset) {
|
|
828
|
+
const box = boxLengths(inset[1], false, style.fontSize, false, true);
|
|
829
|
+
if (box) style.clipPath = Object.freeze({ inset: box });
|
|
830
|
+
} else if (/^rect\(\s*0(?:px)?\s+0(?:px)?\s+0(?:px)?\s+0(?:px)?\s*\)$/i.test(value)) {
|
|
831
|
+
style.clipPath = Object.freeze({ empty: true });
|
|
832
|
+
}
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
case "color": {
|
|
836
|
+
const color = Bun.color(value, "rgba");
|
|
837
|
+
if (color) style.color = color;
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
case "background-color": {
|
|
841
|
+
const color = Bun.color(value, "rgba");
|
|
842
|
+
if (color) style.backgroundColor = color;
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
case "background": {
|
|
846
|
+
// The shorthand resets both longhands; only the final layer may carry a color.
|
|
847
|
+
const layers = splitTopLevel(value, ",");
|
|
848
|
+
const images = layers.filter((layer) => GRADIENT.test(layer));
|
|
849
|
+
const color = splitTopLevel(layers.at(-1) ?? "", " ")
|
|
850
|
+
.map((token) => Bun.color(token, "rgba"))
|
|
851
|
+
.find(Boolean);
|
|
852
|
+
style.backgroundColor = color ?? INITIAL.backgroundColor;
|
|
853
|
+
style.backgroundImage = images.length ? images.join(", ") : null;
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
case "background-image": {
|
|
857
|
+
if (value === "none") style.backgroundImage = null;
|
|
858
|
+
else {
|
|
859
|
+
const images = splitTopLevel(value, ",").filter((layer) => GRADIENT.test(layer));
|
|
860
|
+
if (images.length) style.backgroundImage = images.join(", ");
|
|
861
|
+
}
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
case "box-shadow": {
|
|
865
|
+
const shadows = value === "none" ? null : parseBoxShadows(value, style.fontSize);
|
|
866
|
+
if (value === "none" || shadows) style.boxShadow = shadows;
|
|
867
|
+
break;
|
|
868
|
+
}
|
|
869
|
+
case "background-clip":
|
|
870
|
+
case "-webkit-background-clip":
|
|
871
|
+
if (["border-box", "padding-box", "content-box", "text"].includes(value)) style.backgroundClip = value;
|
|
872
|
+
break;
|
|
873
|
+
case "font-size": {
|
|
874
|
+
const parentSize = parentStyle?.fontSize ?? INITIAL.fontSize;
|
|
875
|
+
const length = FONT_SIZE_KEYWORDS[value] ?? (value === "larger" ? parentSize * 1.2 : value === "smaller" ? parentSize / 1.2
|
|
876
|
+
: computedLength(value, parentSize));
|
|
877
|
+
if (length > 0) style.fontSize = length;
|
|
878
|
+
break;
|
|
879
|
+
}
|
|
880
|
+
case "font":
|
|
881
|
+
case "font-parts": {
|
|
882
|
+
// CSS Fonts 4 §3.7: [style] [variant] [weight] [stretch] size[/line-height] family.
|
|
883
|
+
// Omitted parts reset to their initial values; system fonts are not supported.
|
|
884
|
+
// ("font-parts" is the shorthand without its size, used by the cascade.)
|
|
885
|
+
const parsed = parseFontShorthand(value);
|
|
886
|
+
if (!parsed) break;
|
|
887
|
+
if (name === "font") setProperty(style, "font-size", parsed.size, parentStyle);
|
|
888
|
+
setProperty(style, "line-height", parsed.lineHeight ?? "normal", parentStyle);
|
|
889
|
+
setProperty(style, "font-weight", parsed.weight ?? "normal", parentStyle);
|
|
890
|
+
setProperty(style, "font-family", parsed.family, parentStyle);
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
case "position":
|
|
894
|
+
if (["static", "relative", "absolute", "fixed", "sticky"].includes(value)) style.position = value;
|
|
895
|
+
break;
|
|
896
|
+
case "top":
|
|
897
|
+
case "right":
|
|
898
|
+
case "bottom":
|
|
899
|
+
case "left": {
|
|
900
|
+
const length = value === "auto" ? "auto" : computedLength(value, style.fontSize, true);
|
|
901
|
+
if (length === "auto" || Number.isFinite(length) || length?.unit) style.inset = style.inset.with(BOX_SIDES.indexOf(name), length);
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
case "inset": {
|
|
905
|
+
const parts = splitTopLevel(value, " ").filter(Boolean)
|
|
906
|
+
.map((part) => part === "auto" ? "auto" : computedLength(part, style.fontSize, true));
|
|
907
|
+
if (!parts.length || parts.length > 4 || parts.some((part) => part !== "auto" && !Number.isFinite(part) && !part?.unit)) break;
|
|
908
|
+
const [top, right = top, bottom = top, left = right] = parts;
|
|
909
|
+
style.inset = [top, right, bottom, left];
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
912
|
+
case "z-index": {
|
|
913
|
+
const number = Number(value);
|
|
914
|
+
if (value === "auto" || (Number.isInteger(number) && value.trim() !== "")) style.zIndex = value === "auto" ? "auto" : number;
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
case "transform": {
|
|
918
|
+
const transform = value === "none" ? null : parseTranslate(value, style.fontSize);
|
|
919
|
+
if (transform !== undefined) style.transform = transform;
|
|
920
|
+
break;
|
|
921
|
+
}
|
|
922
|
+
case "content": {
|
|
923
|
+
const content = parseContent(value);
|
|
924
|
+
if (content !== undefined) style.content = content;
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
case "list-style-type": if (LIST_STYLE_TYPES.has(value)) style.listStyleType = value; break;
|
|
928
|
+
case "list-style": {
|
|
929
|
+
// Only the marker type is rendered; position and image are ignored.
|
|
930
|
+
const type = value.split(/\s+/).find((token) => LIST_STYLE_TYPES.has(token));
|
|
931
|
+
if (type) style.listStyleType = type;
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
case "font-family": {
|
|
935
|
+
const families = splitTopLevel(value, ",")
|
|
936
|
+
.map((family) => family.replace(/^(["'])(.*)\1$/, "$2").trim())
|
|
937
|
+
.filter(Boolean);
|
|
938
|
+
if (families.length) style.fontFamily = Object.freeze(families);
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
case "font-weight": {
|
|
942
|
+
const weight = value === "bold" ? 700 : value === "normal" ? 400 : Number(value);
|
|
943
|
+
if (Number.isFinite(weight) && weight >= 1 && weight <= 1000) style.fontWeight = weight;
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
case "white-space": if (WHITE_SPACES.has(value)) style.whiteSpace = value; break;
|
|
947
|
+
case "border-spacing": {
|
|
948
|
+
const parts = value.split(/\s+/).map((part) => computedLength(part, style.fontSize));
|
|
949
|
+
if (parts.length <= 2 && parts.every((part) => Number.isFinite(part) && part >= 0)) {
|
|
950
|
+
style.borderSpacing = Object.freeze([parts[0], parts[1] ?? parts[0]]);
|
|
951
|
+
}
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
case "border-collapse":
|
|
955
|
+
if (["separate", "collapse"].includes(value)) style.borderCollapse = value;
|
|
956
|
+
break;
|
|
957
|
+
case "table-layout":
|
|
958
|
+
if (["auto", "fixed"].includes(value)) style.tableLayout = value;
|
|
959
|
+
break;
|
|
960
|
+
case "vertical-align":
|
|
961
|
+
if (VERTICAL_ALIGNS.has(value)) style.verticalAlign = value;
|
|
962
|
+
break;
|
|
963
|
+
case "float":
|
|
964
|
+
if (["none", "left", "right", "inline-start", "inline-end"].includes(value)) {
|
|
965
|
+
style.float = value === "inline-start" ? "left" : value === "inline-end" ? "right" : value;
|
|
966
|
+
}
|
|
967
|
+
break;
|
|
968
|
+
case "overflow-wrap":
|
|
969
|
+
case "word-wrap":
|
|
970
|
+
if (["normal", "break-word", "anywhere"].includes(value)) style.overflowWrap = value;
|
|
971
|
+
break;
|
|
972
|
+
case "word-break":
|
|
973
|
+
if (["normal", "break-all", "keep-all", "break-word"].includes(value)) style.wordBreak = value;
|
|
974
|
+
break;
|
|
975
|
+
case "text-align": {
|
|
976
|
+
const alignment = value === "left" ? "start" : value === "right" ? "end" : value;
|
|
977
|
+
if (["start", "end", "center"].includes(alignment)) style.textAlign = alignment;
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
case "line-height": {
|
|
981
|
+
const numeric = Number(value);
|
|
982
|
+
if (value === "normal") {
|
|
983
|
+
style.lineHeight = null;
|
|
984
|
+
style.lineHeightFactor = null;
|
|
985
|
+
} else if (Number.isFinite(numeric) && numeric > 0) {
|
|
986
|
+
style.lineHeight = numeric * style.fontSize;
|
|
987
|
+
style.lineHeightFactor = numeric;
|
|
988
|
+
} else {
|
|
989
|
+
const length = computedLength(value, style.fontSize);
|
|
990
|
+
if (length > 0) {
|
|
991
|
+
style.lineHeight = length;
|
|
992
|
+
style.lineHeightFactor = null;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
case "margin": {
|
|
998
|
+
const box = boxLengths(value, true, style.fontSize, true);
|
|
999
|
+
if (box) style.margin = box;
|
|
1000
|
+
break;
|
|
1001
|
+
}
|
|
1002
|
+
case "padding": {
|
|
1003
|
+
const box = boxLengths(value, false, style.fontSize, false);
|
|
1004
|
+
if (box) style.padding = box;
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
case "margin-top":
|
|
1008
|
+
case "margin-right":
|
|
1009
|
+
case "margin-bottom":
|
|
1010
|
+
case "margin-left":
|
|
1011
|
+
case "padding-top":
|
|
1012
|
+
case "padding-right":
|
|
1013
|
+
case "padding-bottom":
|
|
1014
|
+
case "padding-left": {
|
|
1015
|
+
const [box, side] = name.split("-");
|
|
1016
|
+
const isMargin = box === "margin";
|
|
1017
|
+
const length = isMargin && value === "auto" ? "auto" : computedLength(value, style.fontSize);
|
|
1018
|
+
if (length === "auto" || (Number.isFinite(length) && (isMargin || length >= 0))) {
|
|
1019
|
+
style[box] = style[box].with(BOX_SIDES.indexOf(side), length);
|
|
1020
|
+
}
|
|
1021
|
+
break;
|
|
1022
|
+
}
|
|
1023
|
+
case "width":
|
|
1024
|
+
case "height": {
|
|
1025
|
+
const length = value === "auto" ? "auto" : computedLength(value, style.fontSize, true);
|
|
1026
|
+
if (length === "auto" || isLength(length)) style[name] = length;
|
|
1027
|
+
break;
|
|
1028
|
+
}
|
|
1029
|
+
case "min-width":
|
|
1030
|
+
case "max-width":
|
|
1031
|
+
case "min-height":
|
|
1032
|
+
case "max-height": {
|
|
1033
|
+
const none = name.startsWith("max-") && value === "none";
|
|
1034
|
+
const length = none ? "none" : computedLength(value, style.fontSize, true);
|
|
1035
|
+
if (none || isLength(length)) {
|
|
1036
|
+
style[{ "min-width": "minWidth", "max-width": "maxWidth", "min-height": "minHeight", "max-height": "maxHeight" }[name]] = length;
|
|
1037
|
+
}
|
|
1038
|
+
break;
|
|
1039
|
+
}
|
|
1040
|
+
case "border":
|
|
1041
|
+
case "border-top":
|
|
1042
|
+
case "border-right":
|
|
1043
|
+
case "border-bottom":
|
|
1044
|
+
case "border-left": {
|
|
1045
|
+
// Shorthands reset width (medium), style (none) and color (currentColor).
|
|
1046
|
+
const parsed = parseBorderShorthand(value, style.fontSize);
|
|
1047
|
+
if (!parsed) break;
|
|
1048
|
+
const sides = name === "border" ? [0, 1, 2, 3] : [BOX_SIDES.indexOf(name.slice(7))];
|
|
1049
|
+
for (const side of sides) {
|
|
1050
|
+
style.borderSpecifiedWidths = style.borderSpecifiedWidths.with(side, parsed.width);
|
|
1051
|
+
style.borderStyles = style.borderStyles.with(side, parsed.style);
|
|
1052
|
+
style.borderColors = style.borderColors.with(side, parsed.color);
|
|
1053
|
+
}
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
case "border-width":
|
|
1057
|
+
case "border-style":
|
|
1058
|
+
case "border-color": {
|
|
1059
|
+
const parts = splitTopLevel(value, " ").filter(Boolean).map((part) => name === "border-width"
|
|
1060
|
+
? borderWidth(part, style.fontSize)
|
|
1061
|
+
: name === "border-style" ? (BORDER_STYLES.has(part) ? part : null) : borderColor(part));
|
|
1062
|
+
if (!parts.length || parts.length > 4 || parts.some((part) => part === undefined || (name !== "border-color" && part == null))) break;
|
|
1063
|
+
const [top, right = top, bottom = top, left = right] = parts;
|
|
1064
|
+
const values = [top, right, bottom, left];
|
|
1065
|
+
if (name === "border-width") style.borderSpecifiedWidths = values;
|
|
1066
|
+
else if (name === "border-style") style.borderStyles = values;
|
|
1067
|
+
else style.borderColors = values;
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
case "border-top-width": case "border-right-width": case "border-bottom-width": case "border-left-width":
|
|
1071
|
+
case "border-top-style": case "border-right-style": case "border-bottom-style": case "border-left-style":
|
|
1072
|
+
case "border-top-color": case "border-right-color": case "border-bottom-color": case "border-left-color": {
|
|
1073
|
+
const [, side, part] = name.split("-");
|
|
1074
|
+
const index = BOX_SIDES.indexOf(side);
|
|
1075
|
+
if (part === "width") {
|
|
1076
|
+
const width = borderWidth(value, style.fontSize);
|
|
1077
|
+
if (width != null) style.borderSpecifiedWidths = style.borderSpecifiedWidths.with(index, width);
|
|
1078
|
+
} else if (part === "style") {
|
|
1079
|
+
if (BORDER_STYLES.has(value)) style.borderStyles = style.borderStyles.with(index, value);
|
|
1080
|
+
} else {
|
|
1081
|
+
const color = borderColor(value);
|
|
1082
|
+
if (color !== undefined) style.borderColors = style.borderColors.with(index, color);
|
|
1083
|
+
}
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
case "border-radius": {
|
|
1087
|
+
// One radius for every corner; percentages resolve against the box at paint time.
|
|
1088
|
+
const length = computedLength(splitTopLevel(value.split("/")[0], " ").filter(Boolean)[0] ?? "", style.fontSize, true);
|
|
1089
|
+
if (length >= 0 || length?.unit === "%") style.borderRadius = length;
|
|
1090
|
+
break;
|
|
1091
|
+
}
|
|
1092
|
+
case "box-sizing": if (["content-box", "border-box"].includes(value)) style.boxSizing = value; break;
|
|
1093
|
+
case "flex-direction": if (["row", "column"].includes(value)) style.flexDirection = value; break;
|
|
1094
|
+
case "flex-wrap": if (["nowrap", "wrap"].includes(value)) style.flexWrap = value; break;
|
|
1095
|
+
case "justify-content": {
|
|
1096
|
+
const justify = FLEX_ALIGNMENT[value] ?? value;
|
|
1097
|
+
if (["normal", "start", "end", "center", "space-between", "space-around", "space-evenly"].includes(justify)) style.justifyContent = justify;
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
case "align-items": {
|
|
1101
|
+
const alignment = FLEX_ALIGNMENT[value] ?? value;
|
|
1102
|
+
if (["normal", "stretch", "start", "end", "center", "baseline"].includes(alignment)) style.alignItems = alignment;
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
case "gap": {
|
|
1106
|
+
const [row, column = row] = splitTopLevel(value, " ").filter(Boolean)
|
|
1107
|
+
.map((part) => part === "normal" ? 0 : computedLength(part, style.fontSize));
|
|
1108
|
+
if (row >= 0 && column >= 0) {
|
|
1109
|
+
style.gap = row;
|
|
1110
|
+
style.rowGap = row;
|
|
1111
|
+
style.columnGap = column;
|
|
1112
|
+
}
|
|
1113
|
+
break;
|
|
1114
|
+
}
|
|
1115
|
+
case "grid-gap": return setProperty(style, "gap", value, parentStyle);
|
|
1116
|
+
case "grid-row-gap": return setProperty(style, "row-gap", value, parentStyle);
|
|
1117
|
+
case "grid-column-gap": return setProperty(style, "column-gap", value, parentStyle);
|
|
1118
|
+
case "grid-template-columns":
|
|
1119
|
+
case "grid-template-rows": {
|
|
1120
|
+
const tracks = value === "none" ? null : parseTrackList(value, style.fontSize);
|
|
1121
|
+
if (value === "none" || tracks) style[name === "grid-template-columns" ? "gridTemplateColumns" : "gridTemplateRows"] = tracks;
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
case "grid-auto-columns":
|
|
1125
|
+
case "grid-auto-rows": {
|
|
1126
|
+
const tracks = parseTrackList(value, style.fontSize);
|
|
1127
|
+
if (tracks?.length && tracks.every((entry) => !entry.repeat)) {
|
|
1128
|
+
style[name === "grid-auto-columns" ? "gridAutoColumns" : "gridAutoRows"] = tracks;
|
|
1129
|
+
}
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
case "grid-auto-flow": {
|
|
1133
|
+
const words = value.split(/\s+/);
|
|
1134
|
+
if (words.every((word) => ["row", "column", "dense"].includes(word))) {
|
|
1135
|
+
style.gridAutoFlow = Object.freeze({ column: words.includes("column"), dense: words.includes("dense") });
|
|
1136
|
+
}
|
|
1137
|
+
break;
|
|
1138
|
+
}
|
|
1139
|
+
case "grid-column-start":
|
|
1140
|
+
case "grid-column-end":
|
|
1141
|
+
case "grid-row-start":
|
|
1142
|
+
case "grid-row-end": {
|
|
1143
|
+
const property = name.replace(/-(\w)/g, (_, letter) => letter.toUpperCase());
|
|
1144
|
+
style[property] = parseGridLine(value);
|
|
1145
|
+
break;
|
|
1146
|
+
}
|
|
1147
|
+
case "grid-column":
|
|
1148
|
+
case "grid-row": {
|
|
1149
|
+
const [start, end] = value.split("/").map((part) => parseGridLine(part.trim()));
|
|
1150
|
+
const axis = name === "grid-column" ? "Column" : "Row";
|
|
1151
|
+
style[`grid${axis}Start`] = start;
|
|
1152
|
+
// A single integer leaves the end auto (spanning one track).
|
|
1153
|
+
style[`grid${axis}End`] = end ?? "auto";
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
case "grid-area": {
|
|
1157
|
+
const [rowStart, columnStart = "auto", rowEnd = "auto", columnEnd = "auto"] = value.split("/")
|
|
1158
|
+
.map((part) => parseGridLine(part.trim()));
|
|
1159
|
+
Object.assign(style, { gridRowStart: rowStart, gridColumnStart: columnStart, gridRowEnd: rowEnd, gridColumnEnd: columnEnd });
|
|
1160
|
+
break;
|
|
1161
|
+
}
|
|
1162
|
+
case "justify-items":
|
|
1163
|
+
case "justify-self": {
|
|
1164
|
+
const alignment = FLEX_ALIGNMENT[value] ?? value;
|
|
1165
|
+
const allowed = name === "justify-items" ? ["normal", "stretch", "start", "end", "center"] : ["auto", "normal", "stretch", "start", "end", "center"];
|
|
1166
|
+
if (allowed.includes(alignment)) style[name === "justify-items" ? "justifyItems" : "justifySelf"] = alignment;
|
|
1167
|
+
break;
|
|
1168
|
+
}
|
|
1169
|
+
case "row-gap":
|
|
1170
|
+
case "column-gap": {
|
|
1171
|
+
const length = value === "normal" ? 0 : computedLength(value, style.fontSize);
|
|
1172
|
+
if (length >= 0) style[name === "row-gap" ? "rowGap" : "columnGap"] = length;
|
|
1173
|
+
break;
|
|
1174
|
+
}
|
|
1175
|
+
case "align-self": {
|
|
1176
|
+
const alignment = FLEX_ALIGNMENT[value] ?? value;
|
|
1177
|
+
if (["auto", "normal", "stretch", "start", "end", "center", "baseline"].includes(alignment)) style.alignSelf = alignment;
|
|
1178
|
+
break;
|
|
1179
|
+
}
|
|
1180
|
+
case "flex-grow":
|
|
1181
|
+
case "flex-shrink": {
|
|
1182
|
+
const number = Number(value);
|
|
1183
|
+
if (value !== "" && Number.isFinite(number) && number >= 0) style[name === "flex-grow" ? "flexGrow" : "flexShrink"] = number;
|
|
1184
|
+
break;
|
|
1185
|
+
}
|
|
1186
|
+
case "flex-basis": {
|
|
1187
|
+
const basis = flexBasis(value, style.fontSize);
|
|
1188
|
+
if (basis != null) style.flexBasis = basis;
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1191
|
+
case "flex": {
|
|
1192
|
+
const flex = flexShorthand(value, style.fontSize);
|
|
1193
|
+
if (flex) Object.assign(style, flex);
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Rules bucketed by the rightmost compound selector's id, class, attribute
|
|
1201
|
+
* name or type (as Blink's RuleSet does), so an element is only matched
|
|
1202
|
+
* against rules that could apply to it. Rules without such a key go to the
|
|
1203
|
+
* universal bucket. Each rule also lists keys its ancestors must carry
|
|
1204
|
+
* (from compounds joined by descendant or child combinators), which rejects
|
|
1205
|
+
* most non-matching rules before the selector engine runs, like Blink's
|
|
1206
|
+
* ancestor Bloom filter.
|
|
1207
|
+
*/
|
|
1208
|
+
class RuleIndex {
|
|
1209
|
+
#byPseudo = new Map();
|
|
1210
|
+
#stamp = 0;
|
|
1211
|
+
|
|
1212
|
+
constructor(rules) {
|
|
1213
|
+
for (const rule of rules) {
|
|
1214
|
+
let buckets = this.#byPseudo.get(rule.pseudo);
|
|
1215
|
+
if (!buckets) {
|
|
1216
|
+
buckets = { id: new Map(), class: new Map(), attr: new Map(), tag: new Map(), universal: [] };
|
|
1217
|
+
this.#byPseudo.set(rule.pseudo, buckets);
|
|
1218
|
+
}
|
|
1219
|
+
const parts = selectorParts(rule.selector);
|
|
1220
|
+
rule.ancestorKeys = parts ? ancestorKeys(parts) : [];
|
|
1221
|
+
rule.seen = 0;
|
|
1222
|
+
const keys = parts ? subjectKeys(parts.compounds.at(-1)) : null;
|
|
1223
|
+
if (!keys) {
|
|
1224
|
+
buckets.universal.push(rule);
|
|
1225
|
+
continue;
|
|
1226
|
+
}
|
|
1227
|
+
for (const key of keys) {
|
|
1228
|
+
const map = buckets[key.kind];
|
|
1229
|
+
const list = map.get(key.name);
|
|
1230
|
+
if (list) list.push(rule);
|
|
1231
|
+
else map.set(key.name, [rule]);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Rules that may match `element` for `pseudo`, in cascade order.
|
|
1238
|
+
* @param {ReturnType<typeof elementKeys>} keys the element's own keys
|
|
1239
|
+
* @param {Map<string, number>} ancestors keys present on its ancestors
|
|
1240
|
+
*/
|
|
1241
|
+
candidates(keys, pseudo, ancestors) {
|
|
1242
|
+
const buckets = this.#byPseudo.get(pseudo);
|
|
1243
|
+
if (!buckets) return [];
|
|
1244
|
+
const lists = [buckets.universal];
|
|
1245
|
+
if (keys.id) lists.push(buckets.id.get(keys.id));
|
|
1246
|
+
for (const name of keys.classes) lists.push(buckets.class.get(name));
|
|
1247
|
+
for (const name of keys.attrs) lists.push(buckets.attr.get(name));
|
|
1248
|
+
if (keys.tag) lists.push(buckets.tag.get(keys.tag));
|
|
1249
|
+
// A rule in several buckets (from :is()) is taken once.
|
|
1250
|
+
const stamp = ++this.#stamp;
|
|
1251
|
+
const result = [];
|
|
1252
|
+
for (const list of lists) {
|
|
1253
|
+
if (!list) continue;
|
|
1254
|
+
for (const rule of list) {
|
|
1255
|
+
if (rule.seen === stamp) continue;
|
|
1256
|
+
rule.seen = stamp;
|
|
1257
|
+
if (rule.ancestorKeys.every((key) => ancestors.has(key))) result.push(rule);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
if (lists.length > 1) result.sort((left, right) => left.order - right.order);
|
|
1261
|
+
return result;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/** The keys an element offers to selectors: id, classes, attribute names, type. */
|
|
1266
|
+
function elementKeys(element) {
|
|
1267
|
+
const id = element.getAttribute?.("id") || null;
|
|
1268
|
+
const className = element.getAttribute?.("class");
|
|
1269
|
+
const classes = className ? [...new Set(className.split(/\s+/))].filter(Boolean) : [];
|
|
1270
|
+
const attrs = [];
|
|
1271
|
+
for (const attribute of element.attributes ?? []) attrs.push(String(attribute.name).toLowerCase());
|
|
1272
|
+
const tag = element.localName ?? element.tagName;
|
|
1273
|
+
return { id, classes, attrs, tag: tag ? String(tag).toLowerCase() : null };
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
/** Ancestor filter keys for an element: "tag", "#id", ".class", "[attr". */
|
|
1277
|
+
function ancestorFilterKeys(keys) {
|
|
1278
|
+
const result = [];
|
|
1279
|
+
if (keys.tag) result.push(keys.tag);
|
|
1280
|
+
if (keys.id) result.push(`#${keys.id}`);
|
|
1281
|
+
for (const name of keys.classes) result.push(`.${name}`);
|
|
1282
|
+
for (const name of keys.attrs) result.push(`[${name}`);
|
|
1283
|
+
return result;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
/**
|
|
1287
|
+
* Splits a complex selector into compounds and the combinators between them
|
|
1288
|
+
* (" ", ">", "+", "~"), ignoring anything inside (), [] and quotes. Returns
|
|
1289
|
+
* null for selectors this does not understand, which are then left unindexed.
|
|
1290
|
+
*/
|
|
1291
|
+
function selectorParts(selector) {
|
|
1292
|
+
const compounds = [];
|
|
1293
|
+
const combinators = [];
|
|
1294
|
+
let current = "";
|
|
1295
|
+
let pending = null;
|
|
1296
|
+
let depth = 0;
|
|
1297
|
+
for (let index = 0; index < selector.length; index++) {
|
|
1298
|
+
const character = selector[index];
|
|
1299
|
+
if (character === "\\") {
|
|
1300
|
+
current += character + (selector[++index] ?? "");
|
|
1301
|
+
continue;
|
|
1302
|
+
}
|
|
1303
|
+
if (character === "\"" || character === "'") {
|
|
1304
|
+
const close = selector.indexOf(character, index + 1);
|
|
1305
|
+
if (close < 0) return null;
|
|
1306
|
+
current += selector.slice(index, close + 1);
|
|
1307
|
+
index = close;
|
|
1308
|
+
continue;
|
|
1309
|
+
}
|
|
1310
|
+
if (character === "(" || character === "[") depth++;
|
|
1311
|
+
else if (character === ")" || character === "]") depth--;
|
|
1312
|
+
if (depth === 0 && (character === " " || character === ">" || character === "+" || character === "~"
|
|
1313
|
+
|| character === "\t" || character === "\n" || character === "\r" || character === "\f")) {
|
|
1314
|
+
if (current) {
|
|
1315
|
+
compounds.push(current);
|
|
1316
|
+
current = "";
|
|
1317
|
+
pending = " ";
|
|
1318
|
+
}
|
|
1319
|
+
if (character === ">" || character === "+" || character === "~") {
|
|
1320
|
+
if (pending === null && compounds.length === 0) return null;
|
|
1321
|
+
pending = character;
|
|
1322
|
+
}
|
|
1323
|
+
continue;
|
|
1324
|
+
}
|
|
1325
|
+
if (pending !== null) {
|
|
1326
|
+
combinators.push(pending);
|
|
1327
|
+
pending = null;
|
|
1328
|
+
}
|
|
1329
|
+
current += character;
|
|
1330
|
+
}
|
|
1331
|
+
if (depth !== 0) return null;
|
|
1332
|
+
if (current) compounds.push(current);
|
|
1333
|
+
else if (pending !== null && compounds.length) return null;
|
|
1334
|
+
return compounds.length ? { compounds, combinators } : null;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
const IDENTIFIER = /^(?:[\w-]|\\[^0-9a-fA-F\s]|[^\x00-\x7f])+/;
|
|
1338
|
+
|
|
1339
|
+
/** An identifier at the start of `text`, unescaped; null when absent or hex-escaped. */
|
|
1340
|
+
function leadingIdentifier(text) {
|
|
1341
|
+
const match = IDENTIFIER.exec(text);
|
|
1342
|
+
if (!match || text[match[0].length] === "\\") return null;
|
|
1343
|
+
return match[0].replace(/\\(.)/g, "$1");
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
/** Keys of one compound selector, from its parts outside () (ids, classes, attribute names, type). */
|
|
1347
|
+
function compoundKeys(compound) {
|
|
1348
|
+
const keys = { ids: [], classes: [], attrs: [], tag: null, pseudo: [] };
|
|
1349
|
+
if (compound.includes("|")) return keys;
|
|
1350
|
+
const tag = /^[a-zA-Z][\w-]*/.exec(compound)?.[0];
|
|
1351
|
+
if (tag) keys.tag = tag.toLowerCase();
|
|
1352
|
+
let depth = 0;
|
|
1353
|
+
for (let index = 0; index < compound.length; index++) {
|
|
1354
|
+
const character = compound[index];
|
|
1355
|
+
if (character === "\\") {
|
|
1356
|
+
index++;
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
if (character === "(") {
|
|
1360
|
+
depth++;
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (character === ")") {
|
|
1364
|
+
depth--;
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
if (depth > 0) continue;
|
|
1368
|
+
if (character === "[") {
|
|
1369
|
+
const name = /^\s*([\w-]+)/.exec(compound.slice(index + 1))?.[1];
|
|
1370
|
+
if (name) keys.attrs.push(name.toLowerCase());
|
|
1371
|
+
// Skip to the closing bracket; quoted values may contain "]", "#" or ".".
|
|
1372
|
+
let quote = null;
|
|
1373
|
+
for (index++; index < compound.length; index++) {
|
|
1374
|
+
const inner = compound[index];
|
|
1375
|
+
if (inner === "\\") index++;
|
|
1376
|
+
else if (quote) {
|
|
1377
|
+
if (inner === quote) quote = null;
|
|
1378
|
+
} else if (inner === "\"" || inner === "'") quote = inner;
|
|
1379
|
+
else if (inner === "]") break;
|
|
1380
|
+
}
|
|
1381
|
+
} else if (character === "#" || character === ".") {
|
|
1382
|
+
const name = leadingIdentifier(compound.slice(index + 1));
|
|
1383
|
+
if (name && !(character === "." && /^\d/.test(name))) (character === "#" ? keys.ids : keys.classes).push(name);
|
|
1384
|
+
} else if (character === ":") {
|
|
1385
|
+
const name = /^:?([\w-]+)/.exec(compound.slice(index + 1))?.[1];
|
|
1386
|
+
if (name) keys.pseudo.push({ name: name.toLowerCase(), start: index });
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
return keys;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Bucket keys for the subject compound: one id, class, attribute or type key,
|
|
1394
|
+
* or one per alternative of an :is()/:where() whose alternatives all have one.
|
|
1395
|
+
*/
|
|
1396
|
+
function subjectKeys(compound) {
|
|
1397
|
+
const keys = compoundKeys(compound);
|
|
1398
|
+
if (keys.ids.length) return [{ kind: "id", name: keys.ids[0] }];
|
|
1399
|
+
if (keys.classes.length) return [{ kind: "class", name: keys.classes[0] }];
|
|
1400
|
+
if (keys.attrs.length) return [{ kind: "attr", name: keys.attrs[0] }];
|
|
1401
|
+
if (keys.tag) return [{ kind: "tag", name: keys.tag }];
|
|
1402
|
+
if (keys.pseudo.some(({ name }) => name === "root")) return [{ kind: "tag", name: "html" }];
|
|
1403
|
+
for (const { name, start } of keys.pseudo) {
|
|
1404
|
+
if (!["is", "where", "matches", "-webkit-any"].includes(name)) continue;
|
|
1405
|
+
const open = compound.indexOf("(", start);
|
|
1406
|
+
const close = open < 0 ? -1 : matchingParenthesis(compound, open);
|
|
1407
|
+
if (close < 0) return null;
|
|
1408
|
+
const alternatives = splitTopLevel(compound.slice(open + 1, close), ",").filter(Boolean);
|
|
1409
|
+
const result = [];
|
|
1410
|
+
for (const alternative of alternatives) {
|
|
1411
|
+
// Only simple alternatives: complex ones inside :is() are left to the
|
|
1412
|
+
// selector engine unindexed, so indexing never changes a result.
|
|
1413
|
+
const parts = selectorParts(alternative.trim());
|
|
1414
|
+
const inner = parts?.compounds.length === 1 ? subjectKeys(parts.compounds[0]) : null;
|
|
1415
|
+
if (!inner) return null;
|
|
1416
|
+
result.push(...inner);
|
|
1417
|
+
}
|
|
1418
|
+
return result.length ? result : null;
|
|
1419
|
+
}
|
|
1420
|
+
return null;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/** Keys that must be present on some ancestor for the selector to match. */
|
|
1424
|
+
function ancestorKeys(parts) {
|
|
1425
|
+
const keys = new Set();
|
|
1426
|
+
for (let index = 0; index < parts.compounds.length - 1; index++) {
|
|
1427
|
+
// Only compounds whose right-hand combinator is descendant or child are
|
|
1428
|
+
// ancestors of the subject (a sibling's parent is the subject's parent).
|
|
1429
|
+
if (parts.combinators[index] !== " " && parts.combinators[index] !== ">") continue;
|
|
1430
|
+
const compound = compoundKeys(parts.compounds[index]);
|
|
1431
|
+
if (compound.tag) keys.add(compound.tag);
|
|
1432
|
+
for (const id of compound.ids) keys.add(`#${id}`);
|
|
1433
|
+
for (const name of compound.classes) keys.add(`.${name}`);
|
|
1434
|
+
for (const name of compound.attrs) keys.add(`[${name}`);
|
|
1435
|
+
}
|
|
1436
|
+
return [...keys];
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
function matchingParenthesis(text, open) {
|
|
1440
|
+
let depth = 0;
|
|
1441
|
+
for (let index = open; index < text.length; index++) {
|
|
1442
|
+
if (text[index] === "\\") index++;
|
|
1443
|
+
else if (text[index] === "(") depth++;
|
|
1444
|
+
else if (text[index] === ")" && --depth === 0) return index;
|
|
1445
|
+
}
|
|
1446
|
+
return -1;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
function cascadeDeclarations(element, rules, pseudo = null, keys = elementKeys(element), ancestors = new Map()) {
|
|
1450
|
+
const result = new Map();
|
|
1451
|
+
result.hasCustomProperties = false;
|
|
1452
|
+
for (const rule of rules.candidates(keys, pseudo, ancestors)) {
|
|
1453
|
+
if (!matchesSelector(element, rule)) continue;
|
|
1454
|
+
if (rule.hasCustomProperties) result.hasCustomProperties = true;
|
|
1455
|
+
for (const declaration of rule.declarationList) {
|
|
1456
|
+
const candidate = { ...declaration, specificity: rule.specificity, order: rule.order, layer: rule.layer ?? Infinity };
|
|
1457
|
+
const current = result.get(candidate.name);
|
|
1458
|
+
if (!current || compareCascade(candidate, current) >= 0) result.set(candidate.name, candidate);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return result;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
function compareCascade(left, right) {
|
|
1465
|
+
if (left.important !== right.important) return left.important ? 1 : -1;
|
|
1466
|
+
// Cascade layers: later layers and unlayered styles win for normal
|
|
1467
|
+
// declarations; for !important the order is reversed.
|
|
1468
|
+
const leftLayer = left.layer ?? Infinity;
|
|
1469
|
+
const rightLayer = right.layer ?? Infinity;
|
|
1470
|
+
if (leftLayer !== rightLayer) return (leftLayer > rightLayer ? 1 : -1) * (left.important ? -1 : 1);
|
|
1471
|
+
if (left.specificity !== right.specificity) return left.specificity - right.specificity;
|
|
1472
|
+
return left.order - right.order;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
const PSEUDO_ELEMENT = /(?:::?(before|after)|::([\w-]+))$/i;
|
|
1476
|
+
|
|
1477
|
+
/**
|
|
1478
|
+
* Splits a trailing pseudo-element off a selector. Returns pseudo null for
|
|
1479
|
+
* element selectors, "before"/"after" for generated content, and undefined for
|
|
1480
|
+
* pseudo-elements that are not rendered (::placeholder, ::selection, ...).
|
|
1481
|
+
*/
|
|
1482
|
+
function splitPseudoElement(selectorText) {
|
|
1483
|
+
const match = PSEUDO_ELEMENT.exec(selectorText);
|
|
1484
|
+
if (!match) return { selector: selectorText, pseudo: null };
|
|
1485
|
+
const selector = selectorText.slice(0, match.index).trim() || "*";
|
|
1486
|
+
return { selector, pseudo: match[1] ? match[1].toLowerCase() : undefined };
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
/**
|
|
1490
|
+
* Selectors 4 §16 specificity as a*10000 + b*100 + c. :is()/:not()/:has()
|
|
1491
|
+
* take their most specific argument, :where() counts zero, and
|
|
1492
|
+
* pseudo-elements count as types.
|
|
1493
|
+
*/
|
|
1494
|
+
function selectorSpecificity(selector) {
|
|
1495
|
+
let a = 0;
|
|
1496
|
+
let b = 0;
|
|
1497
|
+
let c = 0;
|
|
1498
|
+
let text = selector;
|
|
1499
|
+
// Functional pseudo-classes first, replacing each with a neutral placeholder.
|
|
1500
|
+
for (;;) {
|
|
1501
|
+
const match = /:(is|not|has|where|matches|-webkit-any|nth-child|nth-last-child)\(/i.exec(text);
|
|
1502
|
+
if (!match) break;
|
|
1503
|
+
let depth = 1;
|
|
1504
|
+
let index = match.index + match[0].length;
|
|
1505
|
+
for (; index < text.length && depth > 0; index++) {
|
|
1506
|
+
if (text[index] === "(") depth++;
|
|
1507
|
+
else if (text[index] === ")") depth--;
|
|
1508
|
+
}
|
|
1509
|
+
const argument = text.slice(match.index + match[0].length, index - 1);
|
|
1510
|
+
const name = match[1].toLowerCase();
|
|
1511
|
+
if (name.startsWith("nth")) {
|
|
1512
|
+
b++;
|
|
1513
|
+
const of = /\bof\s+(.+)$/i.exec(argument);
|
|
1514
|
+
if (of) [a, b, c] = addSpecificity([a, b, c], maxSpecificity(of[1]));
|
|
1515
|
+
} else if (name !== "where") {
|
|
1516
|
+
[a, b, c] = addSpecificity([a, b, c], maxSpecificity(argument));
|
|
1517
|
+
}
|
|
1518
|
+
text = text.slice(0, match.index) + " " + text.slice(index);
|
|
1519
|
+
}
|
|
1520
|
+
text = text.replace(/\[[^\]]*\]/g, () => {
|
|
1521
|
+
b++;
|
|
1522
|
+
return " ";
|
|
1523
|
+
});
|
|
1524
|
+
a += (text.match(/#[\w-]+/g) ?? []).length;
|
|
1525
|
+
b += (text.match(/\.[\w-]+/g) ?? []).length;
|
|
1526
|
+
const pseudoElements = (text.match(/::[\w-]+|:(?:before|after|first-line|first-letter)\b/gi) ?? []).length;
|
|
1527
|
+
text = text.replace(/::[\w-]+|:(?:before|after|first-line|first-letter)\b/gi, " ");
|
|
1528
|
+
b += (text.match(/:[\w-]+/g) ?? []).length;
|
|
1529
|
+
c += pseudoElements + (text.match(/(?:^|[\s>+~(])[a-z][\w-]*/gi) ?? []).length;
|
|
1530
|
+
return a * 10_000 + b * 100 + c;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function maxSpecificity(list) {
|
|
1534
|
+
const values = splitTopLevel(list, ",").filter(Boolean).map(selectorSpecificity);
|
|
1535
|
+
const max = Math.max(0, ...values);
|
|
1536
|
+
return [Math.floor(max / 10_000), Math.floor(max / 100) % 100, max % 100];
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
function addSpecificity(left, right) {
|
|
1540
|
+
return [left[0] + right[0], left[1] + right[1], left[2] + right[2]];
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
/** Matches through the DOM's own selector engine; invalid selectors never match. */
|
|
1544
|
+
function matchesSelector(element, rule) {
|
|
1545
|
+
if (rule.invalid || typeof element.matches !== "function") return false;
|
|
1546
|
+
try {
|
|
1547
|
+
return element.matches(rule.selector);
|
|
1548
|
+
} catch {
|
|
1549
|
+
rule.invalid = true;
|
|
1550
|
+
return false;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
/** A stand-in for the pseudo-element's originating element when computing its style. */
|
|
1555
|
+
function pseudoElement(pseudo) {
|
|
1556
|
+
return { tagName: `::${pseudo}`, getAttribute: () => null, hasAttribute: () => false };
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* Keeps the translation part of a transform list as { x, y } lengths (px or
|
|
1561
|
+
* percentages of the element's own border box). Other functions are ignored
|
|
1562
|
+
* until transforms are painted with matrices.
|
|
1563
|
+
*/
|
|
1564
|
+
function parseTranslate(value, fontSize) {
|
|
1565
|
+
let x = 0;
|
|
1566
|
+
let y = 0;
|
|
1567
|
+
let found = false;
|
|
1568
|
+
for (const match of value.matchAll(/(translate|translateX|translateY|translate3d)\(([^)]*)\)/gi)) {
|
|
1569
|
+
const args = splitTopLevel(match[2], ",").map((part) => computedLength(part, fontSize, true));
|
|
1570
|
+
if (args.some((part) => !Number.isFinite(part) && !part?.unit)) return undefined;
|
|
1571
|
+
const kind = match[1].toLowerCase();
|
|
1572
|
+
if (kind === "translatey") y = args[0];
|
|
1573
|
+
else {
|
|
1574
|
+
x = args[0];
|
|
1575
|
+
if (kind !== "translatex") y = args[1] ?? 0;
|
|
1576
|
+
}
|
|
1577
|
+
found = true;
|
|
1578
|
+
}
|
|
1579
|
+
return found ? Object.freeze({ x, y }) : null;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
/** Parses `content` into its string, null for none/normal, undefined if unsupported. */
|
|
1583
|
+
function parseContent(value) {
|
|
1584
|
+
if (value === "none" || value === "normal") return null;
|
|
1585
|
+
let text = "";
|
|
1586
|
+
const tokens = value.match(/(["'])(?:\\.|(?!\1)[^\\])*\1|\S+/g) ?? [];
|
|
1587
|
+
for (const token of tokens) {
|
|
1588
|
+
const string = /^(["'])(.*)\1$/s.exec(token);
|
|
1589
|
+
if (!string) return undefined;
|
|
1590
|
+
text += string[2].replace(/\\([0-9a-f]{1,6})\s?|\\(.)/gi, (_, hex, escaped) =>
|
|
1591
|
+
hex ? String.fromCodePoint(parseInt(hex, 16)) : escaped);
|
|
1592
|
+
}
|
|
1593
|
+
return text;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* Substitutes var() references (CSS Variables 1 §3). Fallbacks may contain
|
|
1598
|
+
* commas and nested functions, including other var()s; a reference to an
|
|
1599
|
+
* undefined property without a fallback leaves nothing (the declaration then
|
|
1600
|
+
* has no effect).
|
|
1601
|
+
*/
|
|
1602
|
+
function resolveVariables(value, customProperties, seen = new Set()) {
|
|
1603
|
+
const text = String(value);
|
|
1604
|
+
// Most values use no custom properties; skip the parsing.
|
|
1605
|
+
if (!text.includes("var(")) return text.trim();
|
|
1606
|
+
let result = "";
|
|
1607
|
+
let index = 0;
|
|
1608
|
+
while (index < text.length) {
|
|
1609
|
+
const start = text.indexOf("var(", index);
|
|
1610
|
+
if (start < 0) {
|
|
1611
|
+
result += text.slice(index);
|
|
1612
|
+
break;
|
|
1613
|
+
}
|
|
1614
|
+
// Part of a longer function name such as "somevar(".
|
|
1615
|
+
if (start > 0 && /[\w-]/.test(text[start - 1])) {
|
|
1616
|
+
result += text.slice(index, start + 4);
|
|
1617
|
+
index = start + 4;
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
result += text.slice(index, start);
|
|
1621
|
+
let depth = 1;
|
|
1622
|
+
let end = start + 4;
|
|
1623
|
+
let comma = -1;
|
|
1624
|
+
for (; end < text.length && depth > 0; end++) {
|
|
1625
|
+
const character = text[end];
|
|
1626
|
+
if (character === "(") depth++;
|
|
1627
|
+
else if (character === ")") depth--;
|
|
1628
|
+
else if (character === "," && depth === 1 && comma < 0) comma = end;
|
|
1629
|
+
}
|
|
1630
|
+
if (depth > 0) {
|
|
1631
|
+
// Unbalanced: leave the rest as it is.
|
|
1632
|
+
result += text.slice(start);
|
|
1633
|
+
break;
|
|
1634
|
+
}
|
|
1635
|
+
const inner = text.slice(start + 4, end - 1);
|
|
1636
|
+
const name = (comma < 0 ? inner : text.slice(start + 4, comma)).trim();
|
|
1637
|
+
const fallback = comma < 0 ? null : text.slice(comma + 1, end - 1);
|
|
1638
|
+
const replacement = seen.has(name) ? null : customProperties.get(name);
|
|
1639
|
+
// A property in a reference cycle is invalid: its fallback applies.
|
|
1640
|
+
const substituted = replacement == null ? "" : resolveVariables(replacement, customProperties, new Set([...seen, name]));
|
|
1641
|
+
if (substituted) result += substituted;
|
|
1642
|
+
else if (fallback != null) result += resolveVariables(fallback, customProperties, seen);
|
|
1643
|
+
index = end;
|
|
1644
|
+
}
|
|
1645
|
+
return result.trim();
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
/** Copies a property's computed value from another style (inherit/initial/unset). */
|
|
1649
|
+
function copyProperty(style, name, source) {
|
|
1650
|
+
const text = cssValue(source, name);
|
|
1651
|
+
if (typeof text === "string" && !CSS_WIDE_KEYWORDS.has(text)) {
|
|
1652
|
+
setProperty(style, name, text);
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
const side = /^(margin|padding)-(top|right|bottom|left)$/.exec(name);
|
|
1656
|
+
if (side) {
|
|
1657
|
+
const index = BOX_SIDES.indexOf(side[2]);
|
|
1658
|
+
style[side[1]] = style[side[1]].with(index, source[side[1]][index]);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
// border, border-<side>, border-<width|style|color>, border-<side>-<...>;
|
|
1662
|
+
// not border-radius, border-spacing or border-collapse.
|
|
1663
|
+
const isBorder = /^border(?:-(?:top|right|bottom|left))?(?:-(?:width|style|color))?$/.test(name);
|
|
1664
|
+
const fields = isBorder
|
|
1665
|
+
? BORDER_FIELDS
|
|
1666
|
+
: PROPERTY_FIELDS[name] ?? [name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())];
|
|
1667
|
+
for (const field of fields) {
|
|
1668
|
+
if (Object.hasOwn(INITIAL, field)) style[field] = source[field];
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
function cssValue(style, name) {
|
|
1673
|
+
return ({
|
|
1674
|
+
"background-color": style.backgroundColor,
|
|
1675
|
+
"font-family": style.fontFamily.map((family) => JSON.stringify(family)).join(", "),
|
|
1676
|
+
"font-size": `${style.fontSize}px`,
|
|
1677
|
+
"font-weight": String(style.fontWeight),
|
|
1678
|
+
"line-height": style.lineHeightFactor != null ? String(style.lineHeightFactor)
|
|
1679
|
+
: style.lineHeight == null ? "normal" : `${style.lineHeight}px`,
|
|
1680
|
+
"list-style-type": style.listStyleType,
|
|
1681
|
+
"text-align": style.textAlign,
|
|
1682
|
+
"white-space": style.whiteSpace,
|
|
1683
|
+
})[name] ?? style[name];
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
function pixelLength(value) {
|
|
1687
|
+
if (value === "0") return 0;
|
|
1688
|
+
const match = /^([+-]?(?:\d+\.?\d*|\.\d+))px$/i.exec(String(value));
|
|
1689
|
+
return match ? Number(match[1]) : NaN;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
function computedLength(value, emSize, allowPercentage = false) {
|
|
1693
|
+
const text = String(value).trim();
|
|
1694
|
+
if (allowPercentage) {
|
|
1695
|
+
const percentage = /^([+-]?(?:\d+\.?\d*|\.\d+))%$/.exec(text);
|
|
1696
|
+
if (percentage) return Object.freeze({ unit: "%", value: Number(percentage[1]) });
|
|
1697
|
+
}
|
|
1698
|
+
const absolute = pixelLength(text);
|
|
1699
|
+
if (Number.isFinite(absolute)) return absolute;
|
|
1700
|
+
if (/^calc\(/i.test(text)) {
|
|
1701
|
+
const sum = calcLength(text, emSize);
|
|
1702
|
+
if (!sum || !(sum.percent === 0 || allowPercentage)) return NaN;
|
|
1703
|
+
return sum.percent === 0 ? sum.px : Object.freeze({ unit: "math", kind: "calc", px: sum.px, percent: sum.percent });
|
|
1704
|
+
}
|
|
1705
|
+
const math = /^(clamp|min|max)\((.*)\)$/i.exec(text);
|
|
1706
|
+
if (math) {
|
|
1707
|
+
const kind = math[1].toLowerCase();
|
|
1708
|
+
const values = splitTopLevel(math[2], ",").map((part) => computedLength(part, emSize, allowPercentage));
|
|
1709
|
+
if (!values.length || values.some((part) => !Number.isFinite(part) && !(part?.unit))) return NaN;
|
|
1710
|
+
// Percentages inside math functions resolve at layout time.
|
|
1711
|
+
if (values.some((part) => part?.unit)) {
|
|
1712
|
+
return (kind === "clamp" && values.length !== 3)
|
|
1713
|
+
? NaN
|
|
1714
|
+
: Object.freeze({ unit: "math", kind, values: Object.freeze(values) });
|
|
1715
|
+
}
|
|
1716
|
+
if (kind === "min") return Math.min(...values);
|
|
1717
|
+
if (kind === "max") return Math.max(...values);
|
|
1718
|
+
return values.length === 3 ? Math.max(values[0], Math.min(values[1], values[2])) : NaN;
|
|
1719
|
+
}
|
|
1720
|
+
const relative = /^([+-]?(?:\d+\.?\d*|\.\d+))(rem|em|vw|vh|pt)$/i.exec(text);
|
|
1721
|
+
if (!relative) return NaN;
|
|
1722
|
+
const unit = relative[2].toLowerCase();
|
|
1723
|
+
const scale = unit === "rem" ? environment.rootFontSize
|
|
1724
|
+
: unit === "em" ? emSize
|
|
1725
|
+
: unit === "vw" ? environment.viewportWidth / 100
|
|
1726
|
+
: unit === "vh" ? environment.viewportHeight / 100
|
|
1727
|
+
: 4 / 3;
|
|
1728
|
+
return Number(relative[1]) * scale;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
/**
|
|
1732
|
+
* calc() (CSS Values 4 §10) as { px, percent }: sums and differences of
|
|
1733
|
+
* lengths and percentages, multiplied or divided by numbers, with nested
|
|
1734
|
+
* parentheses and calc(). Percentages resolve at layout time. Returns null
|
|
1735
|
+
* for anything else (such as min() of a percentage inside calc()).
|
|
1736
|
+
*/
|
|
1737
|
+
function calcLength(text, emSize) {
|
|
1738
|
+
const tokens = String(text).match(/[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?(?:%|[a-z]+)?|[a-z-]+\(|[()*/+-]/gi);
|
|
1739
|
+
if (!tokens || tokens.join("").replace(/\s+/g, "") !== String(text).replace(/\s+/g, "")) return null;
|
|
1740
|
+
let index = 0;
|
|
1741
|
+
// Values are { px, percent } (a length) or { number }.
|
|
1742
|
+
const isNumber = (value) => value && "number" in value;
|
|
1743
|
+
function primary() {
|
|
1744
|
+
const token = tokens[index++];
|
|
1745
|
+
if (token === undefined) return null;
|
|
1746
|
+
if (token === "(" || /^calc\($/i.test(token)) {
|
|
1747
|
+
const value = sum();
|
|
1748
|
+
return tokens[index++] === ")" ? value : null;
|
|
1749
|
+
}
|
|
1750
|
+
if (/^(?:min|max|clamp)\($/i.test(token)) {
|
|
1751
|
+
// Pixel-only min()/max()/clamp() inside calc(): hand the call back to computedLength.
|
|
1752
|
+
let depth = 1;
|
|
1753
|
+
const start = index;
|
|
1754
|
+
while (index < tokens.length && depth) {
|
|
1755
|
+
if (tokens[index].endsWith("(")) depth++;
|
|
1756
|
+
else if (tokens[index] === ")") depth--;
|
|
1757
|
+
index++;
|
|
1758
|
+
}
|
|
1759
|
+
const value = computedLength(`${token}${tokens.slice(start, index).join(" ")}`, emSize);
|
|
1760
|
+
return Number.isFinite(value) ? { px: value, percent: 0 } : null;
|
|
1761
|
+
}
|
|
1762
|
+
// A leading sign on a token is only a sign when it follows an operator.
|
|
1763
|
+
const match = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)(%|[a-z]+)?$/i.exec(token);
|
|
1764
|
+
if (!match) return null;
|
|
1765
|
+
const number = Number(match[1]);
|
|
1766
|
+
if (!match[2]) return { number };
|
|
1767
|
+
if (match[2] === "%") return { px: 0, percent: number };
|
|
1768
|
+
const px = computedLength(token, emSize);
|
|
1769
|
+
return Number.isFinite(px) ? { px, percent: 0 } : null;
|
|
1770
|
+
}
|
|
1771
|
+
function product() {
|
|
1772
|
+
let value = primary();
|
|
1773
|
+
while (value && (tokens[index] === "*" || tokens[index] === "/")) {
|
|
1774
|
+
const operator = tokens[index++];
|
|
1775
|
+
const right = primary();
|
|
1776
|
+
if (!right) return null;
|
|
1777
|
+
if (operator === "/") {
|
|
1778
|
+
if (!isNumber(right) || right.number === 0) return null;
|
|
1779
|
+
value = isNumber(value) ? { number: value.number / right.number } : { px: value.px / right.number, percent: value.percent / right.number };
|
|
1780
|
+
} else if (isNumber(value) && isNumber(right)) {
|
|
1781
|
+
value = { number: value.number * right.number };
|
|
1782
|
+
} else if (isNumber(value) || isNumber(right)) {
|
|
1783
|
+
const [length, factor] = isNumber(value) ? [right, value.number] : [value, right.number];
|
|
1784
|
+
value = { px: length.px * factor, percent: length.percent * factor };
|
|
1785
|
+
} else {
|
|
1786
|
+
return null;
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
return value;
|
|
1790
|
+
}
|
|
1791
|
+
function sum() {
|
|
1792
|
+
let value = product();
|
|
1793
|
+
// "a -b" tokenizes as a signed number: treat a signed token after a value as an operator.
|
|
1794
|
+
while (value && index < tokens.length && tokens[index] !== ")") {
|
|
1795
|
+
let operator = tokens[index];
|
|
1796
|
+
if (operator === "+" || operator === "-") {
|
|
1797
|
+
index++;
|
|
1798
|
+
} else if (/^[+-]/.test(operator)) {
|
|
1799
|
+
operator = operator[0];
|
|
1800
|
+
tokens[index] = tokens[index].slice(1);
|
|
1801
|
+
} else {
|
|
1802
|
+
return null;
|
|
1803
|
+
}
|
|
1804
|
+
const right = product();
|
|
1805
|
+
if (!right || isNumber(right) !== isNumber(value)) return null;
|
|
1806
|
+
const sign = operator === "-" ? -1 : 1;
|
|
1807
|
+
value = isNumber(value)
|
|
1808
|
+
? { number: value.number + sign * right.number }
|
|
1809
|
+
: { px: value.px + sign * right.px, percent: value.percent + sign * right.percent };
|
|
1810
|
+
}
|
|
1811
|
+
return value;
|
|
1812
|
+
}
|
|
1813
|
+
const value = sum();
|
|
1814
|
+
if (!value || index !== tokens.length || isNumber(value)) return null;
|
|
1815
|
+
return value;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
/**
|
|
1819
|
+
* Default field sizes: a textarea is `cols` characters wide and at least
|
|
1820
|
+
* `rows` lines tall (it grows with its value instead of scrolling); a text
|
|
1821
|
+
* input is `size` characters wide. Author widths and heights win.
|
|
1822
|
+
*/
|
|
1823
|
+
function applyControlSize(element, control, values) {
|
|
1824
|
+
const attribute = (name, fallback) => {
|
|
1825
|
+
const number = Number.parseInt(element.getAttribute(name) ?? "", 10);
|
|
1826
|
+
return number > 0 ? number : fallback;
|
|
1827
|
+
};
|
|
1828
|
+
const character = values.fontSize * (control === "textarea" ? 0.6 : 0.55);
|
|
1829
|
+
const lineHeight = values.lineHeight ?? values.fontSize * 1.2;
|
|
1830
|
+
const extraWidth = values.padding[1] + values.padding[3] + values.borderWidths[1] + values.borderWidths[3];
|
|
1831
|
+
const extraHeight = values.padding[0] + values.padding[2] + values.borderWidths[0] + values.borderWidths[2];
|
|
1832
|
+
const borderBox = values.boxSizing === "border-box";
|
|
1833
|
+
if (values.width === "auto") {
|
|
1834
|
+
const content = attribute(control === "textarea" ? "cols" : "size", control === "textarea" ? 20 : 20) * character;
|
|
1835
|
+
values.width = borderBox ? content + extraWidth : content;
|
|
1836
|
+
}
|
|
1837
|
+
if (control === "textarea" && values.minHeight === "auto") {
|
|
1838
|
+
const content = attribute("rows", 2) * lineHeight;
|
|
1839
|
+
values.minHeight = borderBox ? content + extraHeight : content;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
/** text-decoration-line: "none" or a list of underline, overline, line-through (blink ignored). */
|
|
1844
|
+
function parseDecorationLines(value) {
|
|
1845
|
+
const tokens = String(value).trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
1846
|
+
if (tokens.length === 1 && tokens[0] === "none") return "none";
|
|
1847
|
+
const lines = tokens.filter((token) => token !== "blink");
|
|
1848
|
+
if (!tokens.length || lines.some((token) => !DECORATION_LINES.has(token)) || new Set(lines).size !== lines.length) return null;
|
|
1849
|
+
return lines.length ? Object.freeze(lines) : "none";
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
/** Parses `box-shadow` layers: [inset] <x> <y> [<blur> [<spread>]] [<color>]. */
|
|
1853
|
+
function parseBoxShadows(value, fontSize) {
|
|
1854
|
+
const shadows = [];
|
|
1855
|
+
for (const layer of splitTopLevel(value, ",")) {
|
|
1856
|
+
const lengths = [];
|
|
1857
|
+
let color = null;
|
|
1858
|
+
let inset = false;
|
|
1859
|
+
for (const token of splitTopLevel(layer, " ").filter(Boolean)) {
|
|
1860
|
+
if (token === "inset") inset = true;
|
|
1861
|
+
else if (Number.isFinite(computedLength(token, fontSize))) lengths.push(computedLength(token, fontSize));
|
|
1862
|
+
else if (Bun.color(token, "rgba")) color = Bun.color(token, "rgba");
|
|
1863
|
+
else return null;
|
|
1864
|
+
}
|
|
1865
|
+
if (lengths.length < 2 || lengths.length > 4 || lengths[2] < 0) return null;
|
|
1866
|
+
const [x, y, blur = 0, spread = 0] = lengths;
|
|
1867
|
+
shadows.push(Object.freeze({ x, y, blur, spread, color: color ?? "rgba(0, 0, 0, 1)", inset }));
|
|
1868
|
+
}
|
|
1869
|
+
return shadows.length ? Object.freeze(shadows) : null;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
/**
|
|
1873
|
+
* Parses a <track-list> into [{ min, max }] and { repeat, tracks } entries.
|
|
1874
|
+
* Breadths are px numbers, percentage/math objects resolved at layout time,
|
|
1875
|
+
* keywords, { fr }, or { fitContent }. Line names are ignored.
|
|
1876
|
+
*/
|
|
1877
|
+
function parseTrackList(value, fontSize) {
|
|
1878
|
+
const entries = [];
|
|
1879
|
+
const tokens = splitTopLevel(value.replace(/\[[^\]]*\]/g, " "), " ").filter(Boolean);
|
|
1880
|
+
for (const token of tokens) {
|
|
1881
|
+
const repeat = /^repeat\((.*)\)$/i.exec(token);
|
|
1882
|
+
if (repeat) {
|
|
1883
|
+
const [countText, trackText] = splitTopLevel(repeat[1], ",");
|
|
1884
|
+
const tracks = trackText ? parseTrackList(trackText, fontSize) : null;
|
|
1885
|
+
if (!tracks?.length || tracks.some((entry) => entry.repeat)) return null;
|
|
1886
|
+
const count = ["auto-fill", "auto-fit"].includes(countText) ? countText : Number(countText);
|
|
1887
|
+
if (typeof count === "number" && !(Number.isInteger(count) && count > 0)) return null;
|
|
1888
|
+
entries.push(Object.freeze({ repeat: count, tracks: Object.freeze(tracks) }));
|
|
1889
|
+
continue;
|
|
1890
|
+
}
|
|
1891
|
+
const track = parseTrackSize(token, fontSize);
|
|
1892
|
+
if (!track) return null;
|
|
1893
|
+
entries.push(track);
|
|
1894
|
+
}
|
|
1895
|
+
return entries.length ? Object.freeze(entries) : null;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
function parseTrackSize(token, fontSize) {
|
|
1899
|
+
const minmax = /^minmax\((.*)\)$/i.exec(token);
|
|
1900
|
+
if (minmax) {
|
|
1901
|
+
const [min, max] = splitTopLevel(minmax[1], ",").map((part) => parseBreadth(part, fontSize));
|
|
1902
|
+
return min != null && max != null && !min.fr ? Object.freeze({ min, max }) : null;
|
|
1903
|
+
}
|
|
1904
|
+
const fit = /^fit-content\((.*)\)$/i.exec(token);
|
|
1905
|
+
if (fit) {
|
|
1906
|
+
const limit = computedLength(fit[1], fontSize, true);
|
|
1907
|
+
return isLength(limit) ? Object.freeze({ min: "auto", max: Object.freeze({ fitContent: limit }) }) : null;
|
|
1908
|
+
}
|
|
1909
|
+
const breadth = parseBreadth(token, fontSize);
|
|
1910
|
+
if (breadth == null) return null;
|
|
1911
|
+
return Object.freeze({ min: breadth.fr ? "auto" : breadth, max: breadth });
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
function parseBreadth(token, fontSize) {
|
|
1915
|
+
if (["auto", "min-content", "max-content"].includes(token)) return token;
|
|
1916
|
+
const fr = /^(\d+\.?\d*|\.\d+)fr$/.exec(token);
|
|
1917
|
+
if (fr) return Object.freeze({ fr: Number(fr[1]) });
|
|
1918
|
+
const length = computedLength(token, fontSize, true);
|
|
1919
|
+
return isLength(length) ? length : null;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
function isLength(value) {
|
|
1923
|
+
return (Number.isFinite(value) && value >= 0) || (value && typeof value === "object" && ["%", "math"].includes(value.unit));
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
function parseGridLine(token) {
|
|
1927
|
+
if (!token || token === "auto") return "auto";
|
|
1928
|
+
const span = /^span\s+(\d+)$|^(\d+)\s+span$/.exec(token);
|
|
1929
|
+
if (span) return Object.freeze({ span: Math.max(1, Number(span[1] ?? span[2])) });
|
|
1930
|
+
const line = Number(token);
|
|
1931
|
+
if (Number.isInteger(line) && line !== 0) return Object.freeze({ line });
|
|
1932
|
+
// Named lines and areas are not supported yet; treat them as auto.
|
|
1933
|
+
return "auto";
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
const BORDER_STYLES = new Set(["none", "hidden", "solid", "dashed", "dotted", "double", "groove", "ridge", "inset", "outset"]);
|
|
1937
|
+
const BORDER_WIDTH_KEYWORDS = Object.freeze({ thin: 1, medium: 3, thick: 5 });
|
|
1938
|
+
|
|
1939
|
+
/** Returns a px width, or null when the token is not a <line-width>. */
|
|
1940
|
+
function borderWidth(token, fontSize) {
|
|
1941
|
+
if (token in BORDER_WIDTH_KEYWORDS) return BORDER_WIDTH_KEYWORDS[token];
|
|
1942
|
+
const length = computedLength(token, fontSize);
|
|
1943
|
+
return Number.isFinite(length) && length >= 0 ? length : null;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
/** Returns an rgba color, null for currentColor, or undefined when invalid. */
|
|
1947
|
+
function borderColor(token) {
|
|
1948
|
+
if (token.toLowerCase() === "currentcolor") return null;
|
|
1949
|
+
return Bun.color(token, "rgba") ?? undefined;
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
function parseBorderShorthand(value, fontSize) {
|
|
1953
|
+
const border = { width: 3, style: "none", color: null };
|
|
1954
|
+
for (const token of splitTopLevel(value, " ").filter(Boolean)) {
|
|
1955
|
+
if (BORDER_STYLES.has(token)) border.style = token;
|
|
1956
|
+
else if (borderWidth(token, fontSize) != null) border.width = borderWidth(token, fontSize);
|
|
1957
|
+
else if (borderColor(token) !== undefined) border.color = borderColor(token);
|
|
1958
|
+
else return null;
|
|
1959
|
+
}
|
|
1960
|
+
return border;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
function flexBasis(value, fontSize) {
|
|
1964
|
+
if (["auto", "content"].includes(value)) return value;
|
|
1965
|
+
const length = computedLength(value, fontSize, true);
|
|
1966
|
+
return isPercentage(length) || length >= 0 ? length : null;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
/** Expands the `flex` shorthand (CSS Flexbox §7.2). */
|
|
1970
|
+
function flexShorthand(value, fontSize) {
|
|
1971
|
+
if (value === "none") return { flexGrow: 0, flexShrink: 0, flexBasis: "auto" };
|
|
1972
|
+
if (value === "auto") return { flexGrow: 1, flexShrink: 1, flexBasis: "auto" };
|
|
1973
|
+
const parts = value.trim().split(/\s+/);
|
|
1974
|
+
const numbers = [];
|
|
1975
|
+
let basis = null;
|
|
1976
|
+
for (const part of parts) {
|
|
1977
|
+
const number = Number(part);
|
|
1978
|
+
if (part !== "" && Number.isFinite(number) && numbers.length < 2 && basis == null) numbers.push(number);
|
|
1979
|
+
else if (basis == null && (basis = flexBasis(part, fontSize)) != null) continue;
|
|
1980
|
+
else return null;
|
|
1981
|
+
}
|
|
1982
|
+
if (!numbers.length && basis == null) return null;
|
|
1983
|
+
// A unitless zero after the factors is a basis, per the grammar.
|
|
1984
|
+
return {
|
|
1985
|
+
flexGrow: numbers[0] ?? 1,
|
|
1986
|
+
flexShrink: numbers[1] ?? 1,
|
|
1987
|
+
flexBasis: basis ?? (numbers.length ? 0 : "auto"),
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
function splitTopLevel(source, separator) {
|
|
1992
|
+
const parts = [];
|
|
1993
|
+
let depth = 0;
|
|
1994
|
+
let start = 0;
|
|
1995
|
+
for (let index = 0; index < source.length; index++) {
|
|
1996
|
+
const character = source[index];
|
|
1997
|
+
if (character === "(") depth++;
|
|
1998
|
+
else if (character === ")") depth--;
|
|
1999
|
+
else if (character === separator && depth === 0) {
|
|
2000
|
+
parts.push(source.slice(start, index).trim());
|
|
2001
|
+
start = index + 1;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
parts.push(source.slice(start).trim());
|
|
2005
|
+
return parts;
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
function boxLengths(value, allowNegative, emSize, allowAuto, allowPercentage = false) {
|
|
2009
|
+
const parts = value.trim().split(/\s+/).map((part) =>
|
|
2010
|
+
allowAuto && part === "auto" ? "auto" : computedLength(part, emSize, allowPercentage));
|
|
2011
|
+
if (parts.length < 1 || parts.length > 4 || parts.some((part) =>
|
|
2012
|
+
part !== "auto" && !isPercentage(part) && (!Number.isFinite(part) || (!allowNegative && part < 0)))) return null;
|
|
2013
|
+
const [top, right = top, bottom = top, left = right] = parts.length === 3
|
|
2014
|
+
? [parts[0], parts[1], parts[2], parts[1]]
|
|
2015
|
+
: parts.length === 2
|
|
2016
|
+
? [parts[0], parts[1], parts[0], parts[1]]
|
|
2017
|
+
: parts;
|
|
2018
|
+
return [top, right, bottom, left];
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
function isPercentage(value) {
|
|
2022
|
+
return value && typeof value === "object" && value.unit === "%";
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
function gradientFallbackColor(value) {
|
|
2026
|
+
const candidates = String(value).match(/#[\da-f]{3,8}\b|rgba?\([^)]*\)|hsla?\([^)]*\)/gi) ?? [];
|
|
2027
|
+
for (const candidate of candidates) {
|
|
2028
|
+
const color = Bun.color(candidate, "rgba");
|
|
2029
|
+
if (color) return color;
|
|
2030
|
+
}
|
|
2031
|
+
return null;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
function splitDeclarations(source) {
|
|
2035
|
+
const parts = [];
|
|
2036
|
+
let quote = "";
|
|
2037
|
+
let depth = 0;
|
|
2038
|
+
let start = 0;
|
|
2039
|
+
for (let index = 0; index <= source.length; index++) {
|
|
2040
|
+
const character = source[index];
|
|
2041
|
+
if (quote) {
|
|
2042
|
+
if (character === "\\") index++;
|
|
2043
|
+
else if (character === quote) quote = "";
|
|
2044
|
+
} else if (character === '"' || character === "'") quote = character;
|
|
2045
|
+
else if (character === "(") depth++;
|
|
2046
|
+
else if (character === ")") depth = Math.max(0, depth - 1);
|
|
2047
|
+
else if ((character === ";" || index === source.length) && depth === 0) {
|
|
2048
|
+
parts.push(source.slice(start, index));
|
|
2049
|
+
start = index + 1;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
return parts;
|
|
2053
|
+
}
|